Summary
Here I used monocle3 (monocle3_0.2.1) to conduct the pseudotime analysis.
CarDEC, scVI and DCA are both deep learning based methods. For each method, we used all genes as the input, the way of Using latetnOne is the standard pipline for monocle3 (denosied count -> normalization -> scaling -> pca dimension reduction -> umap visualization based on pca dimension reduction) and the other method replces the pca by the latent representation and then umap visualization based on latent representation.
============================================================================================
- HVGs raw: Only using highly variable genes (HVG) as the inputs for Monocle3
- All genes raw: Using all genes (HVG) as the inputs for Monocle3
- Using latent: Replceing the
pca by the latent representation and then umap visualization based on latent representation (CarDEC, DCA+combat, scVI and scanorama).
- HVG denoised: Only using denosined expression count from those highly variable genes (HVGs) as the input for monocle3 and then conducted standard pipline of monocle3 (CarDEC, DCA, scVI and scanorama).
- All genes denoised: Used all denoised expression values as the input for monocle3 and then conducted the standard pipline of monocle3 (CarDEC, DCA, and scVI).
options(warn=-1) # turn off warning message globally
.libPaths(c("/home/xiaoxiang/R/x86_64-pc-linux-gnu-library/3.5",.libPaths()))
Sys.setenv(RETICULATE_PYTHON_ENV="/home/xiaoxiang/anaconda3/envs/py36")#="/home/xiaoxiang/.conda/envs/DESCVIR"
Sys.setenv(RETICULATE_PYTHON="/usr/bin/python3")
#RETICULATE_PYTHON="/home/xiaoxiang/anaconda3/bin/python3",
if ("Seurat" %in% loadedNamespaces()) detach("package:Seurat",unload = T)
dyn.load("/home/xiaoxiang/R/x86_64-pc-linux-gnu-library/3.5/sf/libs/sf.so")
#suppressPackageStartupMessages(library(monocle,lib.loc = "/usr/lib/R/monocle_alpha"))# devtools::install_github("")
#devtools::install_github("cole-trapnell-lab/DDRTree", ref="simple-ppt-like",lib="/usr/lib/R/monocle_alpha")
#devtools::install_github("r-spatial/sf") if
#install.packages("~/Downloads/monocle-release-monocle3_alpha/", repos = NULL,lib = "/usr/lib/R/monocle_alpha")
suppressPackageStartupMessages(library(reticulate))
#suppressPackageStartupMessages(library(devtools))
suppressPackageStartupMessages(library(monocle3))
#suppressPackageStartupMessages(library(flexclust))
#suppressPackageStartupMessages(library(mcclust))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(ggjoy))
suppressPackageStartupMessages(library(VGAM))
suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(kableExtra))
#py_install('umap-learn', pip = T, pip_ignore_installed = T)
#import("leiden")
#fig_path="/home/xiaoxiang/Documents/DESC_paper_prepare/DESC_paper_final/formal_revised/figures_sep/"
datadirpath="./"
df_pseudotime_list=list()
# load necessay function
#source("/media/xiaoxiang/D/DESC_reproducible_file/helpfunc_new.R")
#source("/media/xiaoxiang/D/Upenn_computer_backup/Documents/Human_Heart_Project/heart/Heart_result_updated/helpfunc_new.R")
old=theme_set(theme_bw()+theme(strip.background = element_rect(fill="white"),
panel.background = element_blank(),
legend.background = element_blank(),
panel.grid =element_blank()))
BatchKL=function(df,dimensionData=NULL,replicates=200,n_neighbors=100,n_cells=100,batch="BatchID"){
#entropy of batch mixiing
#replicates is the number of boostrap times
#n_neighbors is the number of nearest neighbours of cell(from all batchs)
#n_cells is the number of randomly picked cells
if (is.null(dimensionData)){
tsnedata=as.matrix(df[,c("tSNE_1","tSNE_2")])
}else{
tsnedata=as.matrix(dimensionData)
}
batchdata=factor(as.vector(df[,batch]))
table.batchdata=as.matrix(table(batchdata))[,1]
tmp00=table.batchdata/sum(table.batchdata)#proportation of population
n=dim(df)[1]
KL=sapply(1:replicates,function(x){
bootsamples=sample(1:n,n_cells)
#nearest=nn2(tsnedata,tsnedata[bootsamples,],k=n_neighbors)
nearest=nabor::knn(tsnedata,tsnedata[bootsamples,],k=min(5*length(tmp00),n_neighbors))
KL_x=sapply(1:length(bootsamples),function(y){
id=nearest$nn.idx[y,]
tmp=as.matrix(table(batchdata[id]))[,1]
tmp=tmp/sum(tmp)
return(sum(tmp*log2(tmp/tmp00),na.rm = T))
})
return(mean(KL_x,na.rm = T))
})
return(KL)
}
Convert_to_seurat3=function(adata){
suppressPackageStartupMessages(library("Seurat",lib.loc = "/usr/lib/R/self_library/"))
mtx=py_to_r(adata$X$T$tocsc())
cellinfo=py_to_r(adata$obs)
geneinfo=py_to_r(adata$var)
colnames(mtx)=cellinfo$cellname
rownames(mtx)=rownames(geneinfo)
obj=CreateSeuratObject(mtx,meta.data = cellinfo[,!colnames(cellinfo)%in%c("n_genes","n_counts"),drop=F],min.features = 1)
return(obj)
}
getwd()
[1] "/home/xiaoxiang/Documents/carDEC_paper/CarDEC_new20200421/results_rmarkdown"
get_plot4=function(df00){
p1=ggplot()+geom_point(data =df00,aes(x=UMAP_1,y=UMAP_2,color=FCGR3A),size=0.01)+
scale_color_gradient(low="grey",high="red")+
theme(legend.position = "top")+
guides(color=guide_colorbar(title.vjust = 0.7))
p2=ggplot()+geom_point(data =df00,aes(x=UMAP_1,y=UMAP_2,color=S100A8),size=0.01)+
scale_color_gradient(low="grey",high="red")+
theme(legend.position = "top")+
guides(color=guide_colorbar(title.vjust = 0.7))
p3=ggplot(data =df00,aes(x=pseudotime,y=FCGR3A))+
geom_point(aes(color=BatchID),size=0.01)+
guides(color=guide_legend(override.aes = list(size=5)))+
geom_smooth(aes(color=BatchID),method="gam",formula = y ~ s(x, bs="cs"))+
geom_smooth(color="black",method="gam",formula = y ~ s(x, bs="cs"),size=0.5)+
ggtitle("")+xlab("Pseudotime")+theme(legend.position = "top",
plot.title = element_text(size=18,face="bold",hjust=0.5),
legend.text = element_text(size=15,face="bold"),
plot.margin = unit(c(0,1,0,0),"cm"),
legend.title = element_blank())+
scale_color_brewer(palette = "Set2")
p4=ggplot(data =df00,aes(x=pseudotime,y=S100A8))+
geom_point(aes(color=BatchID),size=0.01)+
guides(color=guide_legend(override.aes = list(size=5)))+
geom_smooth(aes(color=BatchID),method="gam",formula = y ~ s(x, bs="cs"))+
geom_smooth(color="black",method="gam",formula = y ~ s(x, bs="cs"),size=0.5)+
ggtitle("")+xlab("Pseudotime")+theme(legend.position = "top",
plot.title = element_text(size=18,face="bold",hjust=0.5),
legend.text = element_text(size=15,face="bold"),
legend.title = element_blank())+scale_color_brewer(palette = "Set2")
p=egg::ggarrange(p1,p3,p2,p4,ncol=4,draw=F)
return(p)
}
get_plot4_sep=function(df00){
p1=ggplot()+geom_point(data =df00,aes(x=UMAP_1,y=UMAP_2,color=FCGR3A),size=0.01)+
scale_color_gradient(low="grey",high="red")+
theme(legend.position = "top")+
guides(color=guide_colorbar(title.vjust = 0.7))
p2=ggplot()+geom_point(data =df00,aes(x=UMAP_1,y=UMAP_2,color=S100A8),size=0.01)+
scale_color_gradient(low="grey",high="red")+
theme(legend.position = "top")+
guides(color=guide_colorbar(title.vjust = 0.7))
p3=ggplot(data =df00,aes(x=pseudotime,y=FCGR3A))+
geom_point(aes(color=BatchID),size=0.05)+
guides(color=guide_legend(override.aes = list(size=5)))+
geom_smooth(aes(color=BatchID),method="gam",formula = y ~ s(x, bs="cs"))+
geom_smooth(color="black",method="gam",formula = y ~ s(x, bs="cs"),size=0.5)+
ggtitle("")+xlab("Pseudotime")+theme(legend.position = "top",
plot.title = element_text(size=18,face="bold",hjust=0.5),
legend.text = element_text(size=15,face="bold"),
#plot.margin = unit(c(0,1,0,0),"cm"),
legend.title = element_blank())+
scale_color_brewer(palette = "Set2")
p4=ggplot(data =df00,aes(x=pseudotime,y=S100A8))+
geom_point(aes(color=BatchID),size=0.05)+
guides(color=guide_legend(override.aes = list(size=5)))+
geom_smooth(aes(color=BatchID),method="gam",formula = y ~ s(x, bs="cs"))+
geom_smooth(color="black",method="gam",formula = y ~ s(x, bs="cs"),size=0.5)+
ggtitle("")+xlab("Pseudotime")+theme(legend.position = "top",
plot.title = element_text(size=18,face="bold",hjust=0.5),
legend.text = element_text(size=15,face="bold"),
legend.title = element_blank())+
scale_color_brewer(palette = "Set2")
return(list(p1,p2,p3,p4))
}
ad=import("anndata",convert = FALSE)
/home/xiaoxiang/.local/lib/python3.6/site-packages/dask/config.py:161: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
data = yaml.load(f.read()) or {}
adata=ad$read_h5ad("../../dca_test.h5ad")
obj0=Convert_to_seurat3(adata)
obj0=NormalizeData(obj0,verbose = F)
raw.data=obj0@assays$RNA@counts
maprules=c("2017_0801"="T1","2017_1017"="T2","2017_1120"="T3")
maprules
2017_0801 2017_1017 2017_1120
"T1" "T2" "T3"
Here we compared different methods, including DCA and scVI.
hvg_genes=read.table("../final_processed_results/CarDEC_hvg_used.tsv",header = T,sep="\t",stringsAsFactors = F)
hvg_genes=subset(hvg_genes,Variance.Type=="HVG") #top 2000 genes
Monocle3 for raw data
HVGs raw
rr cell.meta.data=obj0@meta.data cell.meta.data\(dataset_batch=plyr::mapvalues(cell.meta.data\)batch_label,names(maprules),maprules) gene_ann=data.frame(gene_short_name = make.unique(rownames(raw.data)),row.names = make.unique(rownames(raw.data))) #pd <- new(,data=cell.meta.data) #fd <- new(,data=gene_ann) cds <- new_cell_data_set(raw.data[rownames(raw.data)%in%hvg_genes$genename,], cell_metadata = cell.meta.data, gene_metadata =gene_ann[gene_ann\(gene_short_name%in%hvg_genes\)genename,,drop=F]) ## Step 1: Normalize and pre-process the data cds <- preprocess_cds(cds, num_dim = 32,method=,norm_method=,verbose = F)
multiple methods tables found for ‘type’
rr ## Step 2: Remove batch effects with cell alignment ##cds <- align_cds(cds, alignment_group = , residual_model_formula_str = NULL) ## Step 3: Reduce the dimensions using UMAP cds <- reduce_dimension(cds,reduction_method = ,preprocess_method=,verbose = F) ## Step 4: Cluster the cells cds <- cluster_cells(cds,reduction_method =,cluster_method = ,verbose = F) # Construct the graph # Note that, for the rest of the code to run, the graph should be fully (partionly) connected ## Step 5: Learn a graph cds <- learn_graph(cds, use_partition = T,verbose = F)
|
| | 0%
|
|==========================================================================================================================================| 100%
|
| | 0%
|
|==========================================================================================================================================| 100%
rr colData(cds)\(clusters=cds@clusters\)UMAP$clusters p1=plot_cells(cds,color_cells_by = ,label_cell_groups = F)+theme(legend.position = ) p2=plot_cells(cds,color_cells_by = ,label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = ) p=cowplot::plot_grid(p1,p2,align = ,ncol = 3)
rr p

rr ## Step 6: Order cells # a helper function to identify the root principal points: get_earliest_principal_node <- function(cds, cluster=c(,)){ root_pr_nodes=sapply(cluster,function(ii){ cell_ids <- which(colData(cds)[, ] %in%ii)
closest_vertex <-cds@principal_graph_aux[[]]$pr_graph_cell_proj_closest_vertex
closest_vertex <- as.matrix(closest_vertex[colnames(cds), ]) root_pr_nodes <-igraph::V(principal_graph(cds)[[]])$name[as.numeric(names(which.max(table(closest_vertex[cell_ids,]))))] }) root_pr_nodes } # root cells ids=get_earliest_principal_node(cds,cluster=c(,,)) cds <- order_cells(cds,root_pr_nodes = ids) #plot_cells(cds,color_cells_by = )
rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_ori_1=plot_cells(cds,color_cells_by = _batch,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )+theme(legend.title = element_blank())
p_ori_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use
Cells aren't colored in a way that allows them to be grouped.
rr p_ori_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_ori=egg::ggarrange(p_ori_1,p_ori_2,p_ori_3,ncol=3,draw=F)
rr # printed how many cells with no pseudotime table(as.numeric(is.infinite(pData(cds)[,c()]))) #0 mean normal pseudotime and 1 means infinity.
0
10878
rr p_monocle_ori

rr cds_exprs=FetchData(obj0,vars = c(3A,100A8)) df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs)) #cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) #df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)/size_factors(cds)))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)raw=df0
- Feature plots of
FCGR3A and S100A8
rr p=get_plot4(df00 = df0)
rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3])
p-value will be approximate in the presence of ties
rr tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.57211, p-value < 2.2e-16
alternative hypothesis: two-sided
rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2])
p-value will be approximate in the presence of ties
rr tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.4611, p-value < 2.2e-16
alternative hypothesis: two-sided
rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.70922, p-value < 2.2e-16
alternative hypothesis: two-sided
rr Stable5[1,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)
All genes raw
cell.meta.data=obj0@meta.data
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann=data.frame(gene_short_name = make.unique(rownames(raw.data)),row.names = make.unique(rownames(raw.data)))
#pd <- new("AnnotatedDataFrame",data=cell.meta.data)
#fd <- new("AnnotatedDataFrame",data=gene_ann)
cds <- new_cell_data_set(raw.data, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
rr p

rr ## Step 6: Order cells # a helper function to identify the root principal points: get_earliest_principal_node <- function(cds, cluster=c(,)){ root_pr_nodes=sapply(cluster,function(ii){ cell_ids <- which(colData(cds)[, ] %in%ii)
closest_vertex <-cds@principal_graph_aux[[]]$pr_graph_cell_proj_closest_vertex
closest_vertex <- as.matrix(closest_vertex[colnames(cds), ]) root_pr_nodes <-igraph::V(principal_graph(cds)[[]])$name[as.numeric(names(which.max(table(closest_vertex[cell_ids,]))))] }) root_pr_nodes } # root cells ids=get_earliest_principal_node(cds,cluster=c(,)) cds <- order_cells(cds,root_pr_nodes = ids) #plot_cells(cds,color_cells_by = )
rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_ori_all_1=plot_cells(cds,color_cells_by = _batch,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )+theme(legend.title = element_blank())
p_ori_all_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use
Cells aren't colored in a way that allows them to be grouped.
rr p_ori_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_ori_all=egg::ggarrange(p_ori_all_1,p_ori_all_2,p_ori_all_3,ncol=3,draw=F)
rr # printed how many cells with no pseudotime table(as.numeric(is.infinite(pData(cds)[,c()]))) #0 mean normal pseudotime and 1 means infinity.
0
10878
rr p_monocle_ori_all

rr cds_exprs=FetchData(obj0,vars = c(3A,100A8)) df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs)) #cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) #df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)/size_factors(cds)))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)raw_all=df0
- Feature plots of
FCGR3A and S100A8
rr p=get_plot4(df00 = df0)
rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3])
p-value will be approximate in the presence of ties
rr tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.92486, p-value < 2.2e-16
alternative hypothesis: two-sided
rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2]) tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.68425, p-value < 2.2e-16
alternative hypothesis: two-sided
rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3])
p-value will be approximate in the presence of ties
rr tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.77509, p-value < 2.2e-16
alternative hypothesis: two-sided
rr Stable5[2,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)
Monocle3 using carDEC
In this section, we will evalutate the performance of carDEC.
Note that: carDEC used all genes and extracted HVG to evaluate.
rr adata=ad$read_h5ad(../final_processed_results/CarDEC Results/adata_CarDEC.h5ad)
rr cell.meta.data=py_to_r(adata\(obs) cell.meta.data\)dataset_batch=plyr::mapvalues(cell.meta.data\(batch_label,names(maprules),maprules) gene_ann0=py_to_r(adata\)var) gene_ann=data.frame(gene_short_name = make.unique(rownames(gene_ann0)), VarianceType=gene_ann0\(`Variance Type`, row.names = make.unique(rownames(gene_ann0))) mtx=t(py_to_r(adata\)layers[‘denoised counts’])) colnames(mtx)=cell.meta.data$cellname rownames(mtx)=rownames(gene_ann) mtx_sizefactor=1e4/colSums(mtx)
Using latent
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
tmp0=py_to_r(adata$obsm["embedding"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
rr p

rr ## Step 6: Order cells # root cells ids=get_earliest_principal_node(cds,cluster=c()) cds <- order_cells(cds, root_pr_nodes=ids) plot_cells(cds,color_cells_by = )
Cells aren't colored in a way that allows them to be grouped.

rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_carDEC_latent_1=plot_cells(cds,color_cells_by = _batch,,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )
p_carDEC_latent_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use
Cells aren't colored in a way that allows them to be grouped.
rr p_carDEC_latent_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_carDEC_latent=egg::ggarrange(p_carDEC_latent_1,p_carDEC_latent_2,p_carDEC_latent_3,ncol=3,draw=F)
rr p_monocle_carDEC_latent

rr #cds_exprs=FetchData(obj0,vars = c(3A,100A8)) #df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs))=1e4/rowSums(mtx) cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)carDEC_latent=df0
- Feature plots of
FCGR3A and S100A8
rr p=get_plot4(df00 = df0)
rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.051982, p-value = 0.0007981
alternative hypothesis: two-sided
rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2]) tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.033595, p-value = 0.01843
alternative hypothesis: two-sided
rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.052437, p-value = 0.0002922
alternative hypothesis: two-sided
rr Stable5[3,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)
HVGs denoised
cds <- new_cell_data_set(mtx[gene_ann$VarianceType=="HVG",], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$VarianceType=="HVG",,drop=F])
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log")
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
rr p

rr ## Step 6: Order cells # root cells ids=get_earliest_principal_node(cds,cluster=c()) cds <- order_cells(cds, root_pr_nodes=ids) #plot_cells(cds,color_cells_by = )
rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_carDEC_denoised_hvg_1 = plot_cells(cds,color_cells_by = _batch,,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )
p_carDEC_denoised_hvg_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use
Cells aren't colored in a way that allows them to be grouped.
rr p_carDEC_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_carDEC_denoised_hvg=egg::ggarrange(p_carDEC_denoised_hvg_1,p_carDEC_denoised_hvg_2,p_carDEC_denoised_hvg_3,ncol=3,draw=F)
rr p_monocle_carDEC_denoised_hvg

rr #cds_exprs=FetchData(obj0,vars = c(3A,100A8)) #df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs)) cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)carDEC_denoised_hvg=df0
- Feature plots of
FCGR3A and S100A8
rr p=get_plot4(df00 = df0)
rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.069253, p-value = 1.855e-06
alternative hypothesis: two-sided
rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2]) tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.066806, p-value = 1.788e-08
alternative hypothesis: two-sided
rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.066796, p-value = 1.196e-06
alternative hypothesis: two-sided
rr Stable5[4,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)
All genes denoised
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
rr p

rr ## Step 6: Order cells # root cells ids=get_earliest_principal_node(cds,cluster=c()) cds <- order_cells(cds, root_pr_nodes=ids) #plot_cells(cds,color_cells_by = )
rr colData(cds)\(pseudotime=pseudotime(cds) colData(cds)\)Pseudotime=colData(cds)\(pseudotime/max(colData(cds)\)pseudotime,na.rm = T) df_den=pData(cds)[,c(,_batch)] df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),]) set.seed(10) theme_use=theme(legend.text = element_text(size=16), legend.title = element_text(size=20)) p_carDEC_denoised_all_1=plot_cells(cds,color_cells_by = _batch,,graph_label_size=0,alpha=1,cell_size = 0.6)+ guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+ theme_use+ theme(legend.position = )
p_carDEC_denoised_all_2=plot_cells(cds,color_cells_by = ,label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+ theme(legend.position = , legend.title = element_text(vjust = 0.2), legend.text = element_text(angle=-50 ), legend.key.height = unit(0.5,), legend.key.width = unit(1,))+ guides(color = guide_colourbar(label.position = ))+theme_use
Cells aren't colored in a way that allows them to be grouped.
rr p_carDEC_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+ scale_y_continuous(expand = c(0,0))+ scale_x_continuous(expand = c(0,0))+ theme(legend.position=)+theme_use p_monocle_carDEC_denoised_all=egg::ggarrange(p_carDEC_denoised_all_1,p_carDEC_denoised_all_2,p_carDEC_denoised_all_3,ncol=3,draw=F)
rr p_monocle_carDEC_denoised_all

rr #cds_exprs=FetchData(obj0,vars = c(3A,100A8)) #df0=data.frame(cbind(pseudotime=pData(cds)\(Pseudotime,cds_exprs)) cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c(\FCGR3A\,\S100A8\),]) df0=data.frame(cbind(pseudotime=pData(cds)\)Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor))) df0\(UMAP_1=reducedDims(cds)\)UMAP[,1] df0\(UMAP_2=reducedDims(cds)\)UMAP[,2] df0\(BatchID=pData(cds)\)dataset_batch df0=df0[is.finite(df0$pseudotime),] df0=df0[order(df0$pseudotime,decreasing = F),,drop=F] df0\(x=df0\)pseudotime/max(df0\(pseudotime) df_pseudotime_list\)carDEC_denoised_all=df0
- Feature plots of
FCGR3A and S100A8
rr p=get_plot4(df00 = df0)
rr p

rr df_den=colData(cds) tt1=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.12681, p-value < 2.2e-16
alternative hypothesis: two-sided
rr tt2=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==1],df_den\(Pseudotime[df_den\)dataset_batch==2]) tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T1\] and df_den$Pseudotime[df_den$dataset_batch == \T2\]
D = 0.069599, p-value = 3.674e-09
alternative hypothesis: two-sided
rr tt3=ks.test(df_den\(Pseudotime[df_den\)dataset_batch==2],df_den\(Pseudotime[df_den\)dataset_batch==3]) tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == \T2\] and df_den$Pseudotime[df_den$dataset_batch == \T3\]
D = 0.064936, p-value = 2.627e-06
alternative hypothesis: two-sided
rr Stable5[5,2:4]=matrix(get_p_new(c(tt1\(p.value,tt2\)p.value,tt3\(p.value),c(tt1\)statistic,tt2\(statistic,tt3\)statistic)),1,3)
Monocle3 using scVI
#adata=ad$read_h5ad("../final_processed_results/scVI Results/monocytes_ALL/adata_all.h5ad")
adata=ad$read_h5ad("../final_processed_results/scVI Results New/monocytes_ALL/adata_all.h5ad")
cell.meta.data=py_to_r(adata$obs)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann0=py_to_r(adata$var)
gene_ann=data.frame(gene_short_name = make.unique(rownames(gene_ann0)),
row.names = make.unique(rownames(gene_ann0)))
mtx=t(py_to_r(adata$X))
colnames(mtx)=cell.meta.data$cellname
rownames(mtx)=rownames(gene_ann)
mtx_sizefactor=1e4/colSums(mtx)
Using latent
#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
tmp0=py_to_r(adata$obsm["X_latent"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("3"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
#saveRDS(cds,file = "cds_scvi.rds")
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_scVI_latent_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_scVI_latent_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
p_scVI_latent_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_scVI_latent_all=egg::ggarrange(p_scVI_latent_all_1,p_scVI_latent_all_2,p_scVI_latent_all_3,ncol=3,draw=F)
p_monocle_scVI_latent_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scVI_latent_all=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.44217, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.22787, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.22133, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[6,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
HVGs denoised
cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("3"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_scvi_denoised_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_scvi_denoised_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
Cells aren't colored in a way that allows them to be grouped.
p_scvi_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_scvi_denoised_hvg=egg::ggarrange(p_scvi_denoised_hvg_1,p_scvi_denoised_hvg_2,p_scvi_denoised_hvg_3,ncol=3,draw=F)
p_monocle_scvi_denoised_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scVI_denosied_hvg=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.516, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.3063, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.22798, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[7,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
All genes denoised
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("3"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
x0=pseudotime(cds)
x0[is.infinite(x0)]=NA
colData(cds)$pseudotime=x0
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_scVI_denoised_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_scVI_denoised_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
p_scVI_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_scVI_denoised_all=egg::ggarrange(p_scVI_denoised_all_1,p_scVI_denoised_all_2,p_scVI_denoised_all_3,ncol=3,draw=F)
p_monocle_scVI_denoised_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scVI_denosied_all=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.52707, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.31699, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.26217, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[8,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
Monocle3 using dca+combat
#adata=ad$read_h5ad("../final_processed_results/dca Results/adata_all.h5ad")
adata=ad$read_h5ad("../final_processed_results/dca Results New/adata_all.h5ad")
cell.meta.data=py_to_r(adata$obs)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann0=py_to_r(adata$var)
gene_ann=data.frame(gene_short_name = make.unique(rownames(gene_ann0)),
row.names = make.unique(rownames(gene_ann0)))
mtx=t(py_to_r(adata$X))
colnames(mtx)=cell.meta.data$cellname
rownames(mtx)=rownames(gene_ann)
mtx_sizefactor=1e4/colSums(mtx)
Using combated latent from dca
#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log")
tmp0=py_to_r(adata$obsm["X_dca_latent"]) #original dca
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA")
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden")
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("4"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
#saveRDS(cds,file="cds_dca.rds")
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_dca_latent_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_dca_latent_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
p_dca_latent_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_dca_latent_all=egg::ggarrange(p_dca_latent_all_1,p_dca_latent_all_2,p_dca_latent_all_3,ncol=3,draw=F)
p_monocle_dca_latent_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$dca_latent_all=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.12069, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.088498, p-value = 1.499e-14
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.14218, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[9,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
HVGs denoised
cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
tmp0=py_to_r(adata$obsm["X_pcahvg"]) #original dca
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("1","3","4"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_dca_denoised_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_dca_denoised_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
p_dca_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_dca_denoised_hvg=egg::ggarrange(p_dca_denoised_hvg_1,p_dca_denoised_hvg_2,p_dca_denoised_hvg_3,ncol=3,draw=F)
p_monocle_dca_denoised_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$dca_denoised_hvg=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.48635, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.099731, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.50313, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[10,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
All genes denoised
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log",verbose = F)
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
tmp0=py_to_r(adata$obsm["X_pcaall"]) #original dca
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("2","4","5"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_dca_denoised_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_dca_denoised_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
p_dca_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_dca_denoised_all=egg::ggarrange(p_dca_denoised_all_1,p_dca_denoised_all_2,p_dca_denoised_all_3,ncol=3,draw=F)
p_monocle_dca_denoised_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,log1p(t(cds_exprs)*mtx_sizefactor)))
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$dca_denoised_all=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.92747, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.14265, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.87006, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[11,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
Monocle3 using MNN
output=readRDS("../final_processed_results/MNN_corrected_all.rds")
mtx=output@assays$data$corrected
cell.meta.data=colData(output)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann=data.frame(gene_short_name = make.unique(rownames(mtx)),
row.names = make.unique(rownames(mtx)))
HVGs denoised
#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,],
cell_metadata = cell.meta.data,
gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
## Step
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log")
#tmp0=py_to_r(adata$obsm["X_dca_latent"])
#colnames(tmp0)=paste0("PC",1:ncol(tmp0))
#reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA")
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden")
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("2","3","4"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
#saveRDS(cds,file="cds_mnn.rds")
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_mnn_denoised_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_mnn_denoised_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
p_mnn_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_mnn_denoised_hvg=egg::ggarrange(p_mnn_denoised_hvg_1,p_mnn_denoised_hvg_2,p_mnn_denoised_hvg_3,ncol=3,draw=F)
p_monocle_mnn_denoised_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)*mtx_sizefactor))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$mnn_denoised_hvg=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.43599, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.73449, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.86706, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[12,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
All genes denoised
output=readRDS("../final_processed_results/MNN_corrected_all.rds")
mtx=output@assays$data$corrected
cell.meta.data=colData(output)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann=data.frame(gene_short_name = make.unique(rownames(mtx)),
row.names = make.unique(rownames(mtx)))
#colnames(mtx)=colData(output)$cellname
#rownames(mtx)=rownames(gene_ann)
#mtx_sizefactor=1e4/colSums(mtx)
#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 32,method="PCA",norm_method="log")
#tmp0=py_to_r(adata$obsm["X_dca_latent"])
#colnames(tmp0)=paste0("PC",1:ncol(tmp0))
#reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA")
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden")
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("6","3","5"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_mnn_denoised_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_mnn_denoised_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
p_mnn_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_mnn_denoised_all=egg::ggarrange(p_mnn_denoised_all_1,p_mnn_denoised_all_2,p_mnn_denoised_all_3,ncol=3,draw=F)
p_monocle_mnn_denoised_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)*mtx_sizefactor))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$mnn_denoised_all=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.37703, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.55184, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.53852, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[13,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
Monocle3 using scanorama
adata=ad$read_h5ad("../final_processed_results/scanorama Results/adata_ALL.h5ad")#
cell.meta.data=py_to_r(adata$obs)
cell.meta.data$dataset_batch=plyr::mapvalues(cell.meta.data$batch_label,names(maprules),maprules)
gene_ann0=py_to_r(adata$raw$var)
gene_ann=data.frame(gene_short_name = make.unique(rownames(gene_ann0)),
row.names = make.unique(rownames(gene_ann0)))
mtx=t(py_to_r(adata$X$tocsc()))#adata$raw
colnames(mtx)=cell.meta.data$cellname
rownames(mtx)=rownames(gene_ann)
mtx_sizefactor=1e4/colSums(mtx)
Using latent
#mtx=mtx[gene_ann$VarianceType=="HVG",]
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 50,method="PCA",norm_method="log")
tmp0=py_to_r(adata$obsm["X_scanorama"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA")
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden")
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("2"))#need to specify
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
#saveRDS(cds,file="cds_scanorama.rds")
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_monocle_scanorama_latent_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_monocle_scanorama_latent_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
Cells aren't colored in a way that allows them to be grouped.
p_monocle_scanorama_latent_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_scanorama_latent_hvg=egg::ggarrange(p_monocle_scanorama_latent_hvg_1,p_monocle_scanorama_latent_hvg_2,p_monocle_scanorama_latent_hvg_3,ncol=3,draw=F)
p_monocle_scanorama_latent_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scanorama_latent_hvg=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.18479, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.34817, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.19376, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[14,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
HVGs denoised
#cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 50,method="PCA",norm_method="log",verbose = F)
tmp0=py_to_r(adata$obsm["X_hvgpca"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
|
| | 0%
|
|====================================================================================================================| 100%
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("2"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_monocle_scanorama_denoised_hvg_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_monocle_scanorama_denoised_hvg_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
Cells aren't colored in a way that allows them to be grouped.
p_monocle_scanorama_denoised_hvg_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_scanorama_denoised_hvg=egg::ggarrange(p_monocle_scanorama_denoised_hvg_1,p_monocle_scanorama_denoised_hvg_2,p_monocle_scanorama_denoised_hvg_3,ncol=3,draw=F)
p_monocle_scanorama_denoised_hvg

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)*mtx_sizefactor))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scanorama_denoised_hvg=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.18717, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.30887, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.49383, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[15,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
All genes denoised
#cds <- new_cell_data_set(mtx[rownames(mtx)%in%hvg_genes$genename,], cell_metadata = cell.meta.data,gene_metadata =gene_ann[gene_ann$gene_short_name%in%hvg_genes$genename,,drop=F])
cds <- new_cell_data_set(mtx, cell_metadata = cell.meta.data,gene_metadata =gene_ann)
## Step 1: Normalize and pre-process the data
cds <- preprocess_cds(cds, num_dim = 30,method="PCA",norm_method="log",verbose = F)
tmp0=py_to_r(adata$obsm["X_pca"])
colnames(tmp0)=paste0("PC",1:ncol(tmp0))
reducedDims(cds)$PCA=tmp0[,1:30]
## Step 2: Remove batch effects with cell alignment
##cds <- align_cds(cds, alignment_group = "BatchID", residual_model_formula_str = NULL)
## Step 3: Reduce the dimensions using UMAP
cds <- reduce_dimension(cds,reduction_method = "UMAP",preprocess_method="PCA",verbose = F)
## Step 4: Cluster the cells
cds <- cluster_cells(cds,reduction_method ="UMAP",cluster_method = "leiden",verbose = F)
# Construct the graph
# Note that, for the rest of the code to run, the graph should be fully (partionly) connected
## Step 5: Learn a graph
cds <- learn_graph(cds, use_partition = T,verbose = F)
colData(cds)$clusters=cds@clusters$UMAP$clusters
p1=plot_cells(cds,color_cells_by = "partition",label_cell_groups = F)+theme(legend.position = "top")
p2=plot_cells(cds,color_cells_by = "clusters",label_cell_groups=F,graph_label_size=2, label_leaves=F,label_branch_points=F)+theme(legend.position = "top")
p=cowplot::plot_grid(p1,p2,align = "h",ncol = 3)
p

## Step 6: Order cells
# root cells
ids=get_earliest_principal_node(cds,cluster=c("1"))
cds <- order_cells(cds, root_pr_nodes=ids)
#plot_cells(cds,color_cells_by = "pseudotime")
colData(cds)$pseudotime=pseudotime(cds)
colData(cds)$Pseudotime=colData(cds)$pseudotime/max(colData(cds)$pseudotime,na.rm = T)
df_den=pData(cds)[,c("Pseudotime","dataset_batch")]
df_den=as.data.frame(df_den[!is.infinite(df_den$Pseudotime),])
set.seed(10)
theme_use=theme(legend.text = element_text(size=16),
legend.title = element_text(size=20))
p_monocle_scanorama_denoised_all_1=plot_cells(cds,color_cells_by = "dataset_batch",,graph_label_size=0,alpha=1,cell_size = 0.6)+
guides(colour = guide_legend(override.aes = list(alpha=0.7, size=5)))+
theme_use+
theme(legend.position = "top")
p_monocle_scanorama_denoised_all_2=plot_cells(cds,color_cells_by = "Pseudotime",label_branch_points=T,graph_label_size=2,alpha=1,cell_size = 0.6)+
theme(legend.position = "top",
legend.title = element_text(vjust = 0.2),
legend.text = element_text(angle=-50 ),
legend.key.height = unit(0.5,"cm"),
legend.key.width = unit(1,"cm"))+
guides(color = guide_colourbar(label.position = "top"))+theme_use
Cells aren't colored in a way that allows them to be grouped.
p_monocle_scanorama_denoised_all_3=ggplot(data=df_den)+geom_density(aes(x=Pseudotime,fill=dataset_batch),alpha=0.7)+
scale_y_continuous(expand = c(0,0))+
scale_x_continuous(expand = c(0,0))+
theme(legend.position="top")+theme_use
p_monocle_scanorama_denoised_all=egg::ggarrange(p_monocle_scanorama_denoised_all_1,p_monocle_scanorama_denoised_all_2,p_monocle_scanorama_denoised_all_3,ncol=3,draw=F)
p_monocle_scanorama_denoised_all

#cds_exprs=FetchData(obj0,vars = c("FCGR3A","S100A8"))
#df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,cds_exprs))
cds_exprs=as.matrix(SingleCellExperiment::counts(cds)[c("FCGR3A","S100A8"),])
df0=data.frame(cbind(pseudotime=pData(cds)$Pseudotime,t(cds_exprs)*mtx_sizefactor))
df0$UMAP_1=reducedDims(cds)$UMAP[,1]
df0$UMAP_2=reducedDims(cds)$UMAP[,2]
df0$BatchID=pData(cds)$dataset_batch
df0=df0[is.finite(df0$pseudotime),]
df0=df0[order(df0$pseudotime,decreasing = F),,drop=F]
df0$x=df0$pseudotime/max(df0$pseudotime)
df_pseudotime_list$scanorama_denoised_all=df0
- Feature plots of
FCGR3A and S100A8
p=get_plot4(df00 = df0)
p

df_den=colData(cds)
tt1=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
p-value will be approximate in the presence of ties
tt1
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.14931, p-value < 2.2e-16
alternative hypothesis: two-sided
tt2=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T1"],df_den$Pseudotime[df_den$dataset_batch=="T2"])
p-value will be approximate in the presence of ties
tt2
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T1"] and df_den$Pseudotime[df_den$dataset_batch == "T2"]
D = 0.39706, p-value < 2.2e-16
alternative hypothesis: two-sided
tt3=ks.test(df_den$Pseudotime[df_den$dataset_batch=="T2"],df_den$Pseudotime[df_den$dataset_batch=="T3"])
tt3
Two-sample Kolmogorov-Smirnov test
data: df_den$Pseudotime[df_den$dataset_batch == "T2"] and df_den$Pseudotime[df_den$dataset_batch == "T3"]
D = 0.29988, p-value < 2.2e-16
alternative hypothesis: two-sided
Stable5[16,2:4]=matrix(get_p_new(c(tt1$p.value,tt2$p.value,tt3$p.value),c(tt1$statistic,tt2$statistic,tt3$statistic)),1,3)
suppressPackageStartupMessages(library(cowplot))
#Supplementary Table 5
write.table(Stable5,file="KS_table.csv",sep=",")
openxlsx::write.xlsx(Stable5,file="KS_table.xlsx")
Stable5 %>%
kable() %>%
kable_styling()
| |
Method |
T1.v.s..T2 |
T1.v.s..T3 |
T2.v.s..T3 |
| Raw count HVGs |
Raw count HVGs |
0.572 (<2.2e-16) |
0.461 (<2.2e-16) |
0.709 (<2.2e-16) |
| Raw count All |
Raw count All |
0.925 (<2.2e-16) |
0.684 (<2.2e-16) |
0.775 (<2.2e-16) |
| CarDEC (latent) |
CarDEC (latent) |
0.052 (7.98e-04) |
0.034 (1.84e-02) |
0.052 (2.92e-04) |
| CarDEC (denoised HVGs) |
CarDEC (denoised HVGs) |
0.069 (1.85e-06) |
0.067 (1.79e-08) |
0.067 (1.2e-06) |
| CarDEC (denoised All) |
CarDEC (denoised All) |
0.127 (<2.2e-16) |
0.07 (3.67e-09) |
0.065 (2.63e-06) |
| scVI (latent) |
scVI (latent) |
0.442 (<2.2e-16) |
0.228 (<2.2e-16) |
0.221 (<2.2e-16) |
| scVI (denoised HVGs) |
scVI (denoised HVGs) |
0.516 (<2.2e-16) |
0.306 (<2.2e-16) |
0.228 (<2.2e-16) |
| scVI (denoised All) |
scVI (denoised All) |
0.527 (<2.2e-16) |
0.317 (<2.2e-16) |
0.262 (<2.2e-16) |
| DCA (latent) |
DCA (latent) |
0.121 (<2.2e-16) |
0.088 (1.5e-14) |
0.142 (<2.2e-16) |
| DCA (denoised HVGs) |
DCA (denoised HVGs) |
0.486 (<2.2e-16) |
0.1 (<2.2e-16) |
0.503 (<2.2e-16) |
| DCA (denoised All) |
DCA (denoised All) |
0.927 (<2.2e-16) |
0.143 (<2.2e-16) |
0.87 (<2.2e-16) |
| MNN (denoised HVGs) |
MNN (denoised HVGs) |
0.436 (<2.2e-16) |
0.734 (<2.2e-16) |
0.867 (<2.2e-16) |
| MNN (denoised All) |
MNN (denoised All) |
0.377 (<2.2e-16) |
0.552 (<2.2e-16) |
0.539 (<2.2e-16) |
| Scanorama (latent) |
Scanorama (latent) |
0.185 (<2.2e-16) |
0.348 (<2.2e-16) |
0.194 (<2.2e-16) |
| Scanorama (denoised HVGs) |
Scanorama (denoised HVGs) |
0.187 (<2.2e-16) |
0.309 (<2.2e-16) |
0.494 (<2.2e-16) |
| Scanorama (denoised All) |
Scanorama (denoised All) |
0.149 (<2.2e-16) |
0.397 (<2.2e-16) |
0.3 (<2.2e-16) |
Figures
Main Figure (Figure 5)
fig_width=30
fig_height=25
labels=letters[1:5]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(4,15,10,7,12)
get_draw_plot=function(plot_id=1,plist0){
x=0.02
y=1-plot_id/5
width=0.98
height=1/5-0.01 # total number of figures is 12
pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(pp)
}
get_label_pos=function(plot_id=1){
x=0
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/5-1/30))
}
get_title_pos=function(plot_id=1){
x=0.015
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/10-1/60))
}
get_plot_list=function(x,y){
x0=rep(list(),length=length(x)+length(y))
x0[1:length(x)]=x[1:3]
x0[(length(x)+1):length(x0)]=y[1:2]
return(x0)
}
p=ggdraw()+get_draw_plot(1,get_plot_list(list(p_carDEC_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_carDEC_denoised_hvg_2,
p_carDEC_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[4]])[c(3,4)]))+
get_draw_plot(2,get_plot_list(list(p_monocle_scanorama_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_monocle_scanorama_denoised_hvg_2,
p_monocle_scanorama_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[15]])[c(3,4)]))+
get_draw_plot(3,get_plot_list(list(p_dca_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_dca_denoised_hvg_2,
p_dca_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[10]])[c(3,4)]))+
get_draw_plot(4,get_plot_list(list(p_scvi_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_scvi_denoised_hvg_2,
p_scvi_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[7]])[c(3,4)]))+
get_draw_plot(5,get_plot_list(list(p_mnn_denoised_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_mnn_denoised_hvg_2,
p_mnn_denoised_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[12]])[c(3,4)]))
for (i in 1:length(use_id)){
p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
draw_label(paste0(Methods[use_id[i]],collapse = ""),
x=get_title_pos(i)[1],
y=get_title_pos(i)[2],
size=20,
color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Main_fig1.pdf",width = 30,height = 25)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Main_fig1.tiff",width = 30,height = 25,compression="lzw")
Supplementary Figures about monocyte
- Raw
plist0=rep(list(),length=9)
plist0[1:3]=list(p_ori_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2")+theme_use,
p_ori_all_2,
p_ori_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")+theme(plot.margin = unit(c(0,0,1,0),"cm")))[1:3]
plist0[4:5]=get_plot4_sep(df_pseudotime_list[[2]])[1:2]
plist0[[6]]=ggplot()+theme_void()+theme(plot.margin = unit(c(0,0,1,0),"cm"))
plist0[7:8]=get_plot4_sep(df_pseudotime_list[[2]])[3:4]
plist0[[9]]=ggplot()+theme_void()
p=ggdraw()+draw_plot(egg::ggarrange(plots = plist0,ncol=3,draw = F),x=0,y=0,width=1,height=1)+
draw_label("a",x=0,y=1-0.02,size=30,color="black",hjust = 0,vjust = 1)+
draw_label("b",x=0,y=2/3-0.03,size=30,color="black",hjust = 0,vjust = 1)+
draw_label("c",x=0,y=1/3-0.03,size=30,color="black",hjust = 0,vjust = 1)
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig1.pdf",width = 18,height = 16)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig1.tiff",width = 18,height = 16,compression="lzw")
- All genes
fig_width=30
fig_height=25
labels=letters[1:5]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(5,16,11,8,13)
get_draw_plot=function(plot_id=1,plist0){
x=0.02
y=1-plot_id/5
width=0.98
height=1/5-0.01 # total number of figures is 12
pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(pp)
}
get_label_pos=function(plot_id=1){
x=0
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/5-1/30))
}
get_title_pos=function(plot_id=1){
x=0.015
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/10-1/60))
}
get_plot_list=function(x,y){
x0=rep(list(),length=length(x)+length(y))
x0[1:length(x)]=x[1:3]
x0[(length(x)+1):length(x0)]=y[1:2]
return(x0)
}
p=ggdraw()+
get_draw_plot(1,get_plot_list(list(p_carDEC_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_carDEC_denoised_all_2,
p_carDEC_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[5]])[c(3,4)]))+
get_draw_plot(2,get_plot_list(list(p_monocle_scanorama_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_monocle_scanorama_denoised_all_2,
p_monocle_scanorama_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[16]])[c(3,4)]))+
get_draw_plot(3,get_plot_list(list(p_dca_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_dca_denoised_all_2,
p_dca_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[11]])[c(3,4)]))+
get_draw_plot(4,get_plot_list(list(p_scVI_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_scVI_denoised_all_2,
p_scVI_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[8]])[c(3,4)]))+
get_draw_plot(5,get_plot_list(list(p_mnn_denoised_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_mnn_denoised_all_2,
p_mnn_denoised_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[13]])[c(3,4)]))
for (i in 1:length(use_id)){
p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
draw_label(paste0(Methods[use_id[i]],collapse = ""),
x=get_title_pos(i)[1],
y=get_title_pos(i)[2],
size=20,
color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig2.pdf",width = 30,height = 25,limitsize = F)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig2.tiff",width = 30,height = 25,limitsize = F,compression="lzw")
- Latent
fig_width=30
fig_height=25
labels=letters[1:5]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(3,14,9,6,1)
get_draw_plot=function(plot_id=1,plist0){
x=0.02
y=1-plot_id/5
width=0.98
height=1/5-0.01 # total number of figures is 12
pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(pp)
}
get_label_pos=function(plot_id=1){
x=0
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/5-1/30))
}
get_title_pos=function(plot_id=1){
x=0.015
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/10-1/60))
}
get_plot_list=function(x,y){
x0=rep(list(),length=length(x)+length(y))
x0[1:length(x)]=x[1:3]
x0[(length(x)+1):length(x0)]=y[1:2]
return(x0)
}
p=ggdraw()+get_draw_plot(1,get_plot_list(list(p_carDEC_latent_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_carDEC_latent_2,
p_carDEC_latent_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[3]])[c(3,4)]))+
get_draw_plot(2,get_plot_list(list(p_monocle_scanorama_latent_hvg_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_monocle_scanorama_latent_hvg_2,
p_monocle_scanorama_latent_hvg_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[14]])[c(3,4)]))+
get_draw_plot(3,get_plot_list(list(p_dca_latent_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_dca_latent_all_2,
p_dca_latent_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[9]])[c(3,4)]))+
get_draw_plot(4,get_plot_list(list(p_scVI_latent_all_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_scVI_latent_all_2,
p_scVI_latent_all_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[6]])[c(3,4)]))+
get_draw_plot(5,get_plot_list(list(p_ori_1+scale_color_brewer(name="dataset_batch",palette = "Set2"),
p_ori_2,
p_ori_3+scale_fill_brewer(name="dataset_batch",palette = "Set2")),
get_plot4_sep(df_pseudotime_list[[1]])[c(3,4)]))
for (i in 1:length(use_id)){
p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
draw_label(paste0(Methods[use_id[i]],collapse = ""),
x=get_title_pos(i)[1],
y=get_title_pos(i)[2],
size=20,
color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig3.pdf",width = 30,height = 25,limitsize = F)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig3.tiff",width = 30,height = 25,limitsize = F,compression="lzw")
S100A8 and FCGR3A’s feature plots
- monocles’ UMAP of denoised counts from HVGs
fig_width=15
fig_height=25
labels=letters[1:13]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(4,15,10,7,12)
#use_id=c(3,9,6,1)
get_draw_plot=function(plot_id=1,plist0){
x=0.02
y=1-plot_id/5
width=0.98
height=1/5-0.01 # total number of figures is 12
pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(pp)
}
get_label_pos=function(plot_id=1){
x=0
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/5-1/100))
}
get_title_pos=function(plot_id=1){
x=0.015
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/10-1/100))
}
get_plot_list=function(x,y){
x0=rep(list(),length=length(x)+length(y))
x0[1:length(x)]=x[1:3]
x0[(length(x)+1):length(x0)]=y[1:2]
return(x0)
}
p=ggdraw()
for(i in 1:length(use_id)){
p=p+get_draw_plot(i,get_plot4_sep(df_pseudotime_list[[use_id[i]]])[c(1,2)])
}
for (i in 1:length(use_id)){
p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
draw_label(paste0(Methods[use_id[i]],collapse = ""),
x=get_title_pos(i)[1],
y=get_title_pos(i)[2],
size=20,
color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig4.pdf",p,width = 15,height = 25)
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig4.tiff",p,width = 15,height = 25,compression="lzw")
p

- monocles’ UMAP of denoised counts from All genes
fig_width=15
fig_height=25
labels=letters[1:13]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(5,16,11,8,13)
get_draw_plot=function(plot_id=1,plist0){
x=0.02
y=1-plot_id/5
width=0.98
height=1/5-0.01 # total number of figures is 12
pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(pp)
}
get_label_pos=function(plot_id=1){
x=0
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/5-1/100))
}
get_title_pos=function(plot_id=1){
x=0.015
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/10-1/100))
}
get_plot_list=function(x,y){
x0=rep(list(),length=length(x)+length(y))
x0[1:length(x)]=x[1:3]
x0[(length(x)+1):length(x0)]=y[1:2]
return(x0)
}
p=ggdraw()
for(i in 1:length(use_id)){
p=p+get_draw_plot(i,get_plot4_sep(df_pseudotime_list[[use_id[i]]])[c(1,2)])
}
for (i in 1:length(use_id)){
p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
draw_label(paste0(Methods[use_id[i]],collapse = ""),
x=get_title_pos(i)[1],
y=get_title_pos(i)[2],
size=20,
color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig5.pdf",p,width = 15,height = 25)
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig5.tiff",p,width = 15,height = 25,compression="lzw")
p

- monocles’ UMAP based on different methods’ latent
fig_width=15
fig_height=25
labels=letters[1:13]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(3,14,9,6,1)
get_draw_plot=function(plot_id=1,plist0){
x=0.02
y=1-plot_id/5
width=0.98
height=1/5-0.01 # total number of figures is 12
pp=draw_plot(egg::ggarrange(plots=plist0,nrow = 1,draw = F,newpage = F),x = x,y = y,width = width,height = height)
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(pp)
}
get_label_pos=function(plot_id=1){
x=0
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/5-1/100))
}
get_title_pos=function(plot_id=1){
x=0.015
y=1-plot_id/5
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/10-1/100))
}
get_plot_list=function(x,y){
x0=rep(list(),length=length(x)+length(y))
x0[1:length(x)]=x[1:3]
x0[(length(x)+1):length(x0)]=y[1:2]
return(x0)
}
p=ggdraw()
for(i in 1:length(use_id)){
p=p+get_draw_plot(i,get_plot4_sep(df_pseudotime_list[[use_id[i]]])[c(1,2)])
}
for (i in 1:length(use_id)){
p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=30,color="black",hjust = 0,vjust = 1)+
draw_label(paste0(Methods[use_id[i]],collapse = ""),
x=get_title_pos(i)[1],
y=get_title_pos(i)[2],
size=20,
color = "black",angle = 90,hjust = 0.5,vjust = 0.5)
}
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig6.pdf",p,width = 15,height = 25)
ggsave("./revised_figures/CarDEC_monocyte_Supp_fig6.tiff",p,width = 15,height = 25,compression="lzw")
p

- Combined above three figures
fig_width=24
fig_height=36#
labels=letters[1:16]
Methods=c("Raw count HVGs","Raw count All","CarDEC (latent)","CarDEC (denoised HVGs)","CarDEC (denoised All)","scVI (latent)","scVI (denoised HVGs)","scVI (denoised All)","DCA (latent)","DCA (denoised HVGs)","DCA (denoised All)","MNN (denoised HVGs)","MNN (denoised All)","Scanorama (latent)","Scanorama (denoised HVGs)","Scanorama (denoised All)")
use_id=c(1,3:5,14:16,6:13)
get_draw_plot=function(plot_id=1,plist0){
x=ifelse(plot_id%%2==1,0,0.5075)
y=1-floor((plot_id+1)/2)/8
width=1/2-0.015
height=1/8-0.01 # total number of figures is 12
pp=draw_plot(egg::ggarrange(plots=plist0,ncol = 2,draw = F,newpage = F),x = x,y = y,width = width,height = height)
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(pp)
}
get_label_pos=function(plot_id=1){
x=ifelse(plot_id%%2==1,0,0.5075)
y=1-floor((plot_id+1)/2)/8
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/8-1/100))
}
get_title_pos=function(plot_id=1){
x=ifelse(plot_id%%2==1,0,0.5075)+0.5/2
y=1-floor((plot_id+1)/2)/8
#draw_label(labels[plot_id],x=x,y=y+1/6,hjust =1,vjust = 0.5,size = 35)
return(c(x,y+1/8-1/300))
}
p=ggdraw()
for(i in 1:length(use_id)){
p=p+get_draw_plot(i,get_plot4_sep(df_pseudotime_list[[use_id[i]]])[c(1,2)])
}
for (i in 1:length(use_id)){
p=p+draw_label(labels[i],x=get_label_pos(i)[1],y=get_label_pos(i)[2],size=18,color="black",hjust = 0,vjust = 1)+
draw_label(paste0(Methods[use_id[i]],collapse = ""),x=get_title_pos(i)[1],y=get_title_pos(i)[2],size=25,color = "black",vjust = 1)
}
p

ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig456_combined.pdf",width = 24,height = 36)
ggsave(p,filename = "./revised_figures/CarDEC_monocyte_Supp_fig456_combined.tiff",width = 24,height = 36,compression="lzw")
#save object
rm(mtx)
rm(output)
rm(adata)
rm(cds)
rm(obj0)
rm(raw.data)
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 7706421 411.6 15080422 805.4 15080422 805.4
Vcells 1642530695 12531.6 3505959062 26748.4 3503411665 26729.0
save.image(file="carDEC_monocyte_final_revised.RData")#include scanorama,carDEC_monocyte_final.RData not include scanorama
load("carDEC_monocyte_final_revised.RData")
sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.3 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_SG.UTF-8 LC_COLLATE=en_US.UTF-8 LC_MONETARY=en_SG.UTF-8
[6] LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_SG.UTF-8 LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_SG.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] grid splines stats4 parallel stats graphics grDevices utils datasets methods base
other attached packages:
[1] mgcv_1.8-28 nlme_3.1-140 monocle3_0.2.1 SingleCellExperiment_1.6.0 SummarizedExperiment_1.14.0
[6] DelayedArray_0.10.0 BiocParallel_1.20.1 matrixStats_0.56.0 GenomicRanges_1.36.0 GenomeInfoDb_1.20.0
[11] IRanges_2.18.3 S4Vectors_0.22.1 pheatmap_1.0.12 pbapply_1.4-2 liger_0.4.2
[16] harmony_1.0 Rcpp_1.0.6 RColorBrewer_1.1-2 patchwork_1.1.0.9000 SeuratWrappers_0.1.0
[21] cowplot_1.0.0 ComplexHeatmap_2.1.2 kableExtra_0.9.0 ggjoy_0.4.1 ggridges_0.5.1
[26] tidyr_0.8.3 dplyr_0.8.5 monocle_2.9.0 DDRTree_0.1.5 irlba_2.3.3
[31] VGAM_1.1-2 ggplot2_3.3.3 Biobase_2.44.0 BiocGenerics_0.32.0 Matrix_1.2-18
[36] reticulate_1.15
loaded via a namespace (and not attached):
[1] rappdirs_0.3.1 RANN.L1_2.5.2 nabor_0.5.0 bit64_0.9-7 knitr_1.23 data.table_1.12.8
[7] rpart_4.1-15 RCurl_1.98-1.1 snow_0.4-3 RSQLite_2.1.1 RANN_2.6.1 europepmc_0.3
[13] combinat_0.0-8 proxy_0.4-23 future_1.12.0 bit_1.1-15.2 enrichplot_1.2.0 spatstat.data_1.4-3
[19] xml2_1.3.0 httpuv_1.5.4 assertthat_0.2.1 viridis_0.5.1 xfun_0.19 hms_0.5.0
[25] evaluate_0.14 promises_1.0.1 fansi_0.4.1 progress_1.2.2 caTools_1.18.0 readxl_1.3.1
[31] igraph_1.2.5 DBI_1.1.0 htmlwidgets_1.3 sparsesvd_0.2 riverplot_0.6 purrr_0.3.3
[37] crosstalk_1.0.0 ggpubr_0.2.1 V8_2.3 deldir_0.1-25 vctrs_0.2.4 remotes_2.1.1
[43] ROCR_1.0-7 abind_1.4-5 withr_2.1.2 ggforce_0.1.3 triebeard_0.3.0 sctransform_0.3.1
[49] prettyunits_1.1.1 mclust_5.4.5 goftest_1.2-2 mnormt_1.5-6 cluster_2.1.0 DOSE_3.8.2
[55] lazyeval_0.2.2 crayon_1.3.4 pkgconfig_2.0.3 slam_0.1-47 labeling_0.3 units_0.6-5
[61] tweenr_1.0.1 rlang_0.4.10 globals_0.12.4 lifecycle_0.2.0 miniUI_0.1.1.1 doSNOW_1.0.18
[67] rsvd_1.0.0 cellranger_1.1.0 polyclip_1.10-0 lmtest_0.9-37 urltools_1.7.2 zoo_1.8-7
[73] base64enc_0.1-3 GlobalOptions_0.1.1 png_0.1-7 viridisLite_0.3.0 rjson_0.2.20 bitops_1.0-6
[79] KernSmooth_2.23-15 blob_1.2.0 shape_1.4.4 pdftools_2.3 stringr_1.4.0 qvalue_2.14.1
[85] qpdf_1.1 readr_1.3.1 gridGraphics_0.5-0 ggsignif_0.5.0 scales_1.1.0 memoise_1.1.0
[91] magrittr_1.5 plyr_1.8.4 ica_1.0-2 gplots_3.0.3 zlibbioc_1.32.0 gdata_2.18.0
[97] compiler_3.6.1 HSMMSingleCell_1.4.0 lsei_1.2-0 clue_0.3-57 fitdistrplus_1.0-14 cli_2.0.2
[103] XVector_0.24.0 listenv_0.7.0 MASS_7.3-51.4 tidyselect_0.2.5 stringi_1.4.6 densityClust_0.3
[109] yaml_2.2.0 GOSemSim_2.8.0 askpass_1.1 ggrepel_0.8.1 fastmatch_1.1-0 randomcoloR_1.1.0.1
[115] tools_3.6.1 future.apply_1.2.0 circlize_0.4.8 rstudioapi_0.11 foreach_1.5.0 gridExtra_2.3
[121] farver_2.0.3 Rtsne_0.15 ggraph_1.0.2 digest_0.6.25 rvcheck_0.1.3 BiocManager_1.30.10
[127] FNN_1.1.3 shiny_1.3.2 qlcMatrix_0.9.7 egg_0.4.5 later_1.0.0 RcppAnnoy_0.0.16
[133] httr_1.4.1 AnnotationDbi_1.48.0 rsconnect_0.8.16 psych_1.9.12.31 npsurv_0.4-0 colorspace_1.4-1
[139] rvest_0.3.4 tensor_1.5 uwot_0.1.8 spatstat.utils_1.17-0 ggplotify_0.0.3 plotly_4.9.0
[145] xtable_1.8-4 jsonlite_1.6.1 spatstat_1.64-1 UpSetR_1.3.3 R6_2.4.1 pillar_1.4.2
[151] htmltools_0.4.0 mime_0.9 glue_1.4.0 clusterProfiler_3.10.1 DT_0.7 codetools_0.2-16
[157] fgsea_1.8.0 utf8_1.1.4 lattice_0.20-38 tibble_2.1.3 curl_4.3 leiden_0.3.1
[163] gtools_3.8.2 magick_2.3 zip_2.0.4 GO.db_3.7.0 openxlsx_4.1.4 survival_2.44-1.1
[169] limma_3.42.2 rmarkdown_1.11 docopt_0.6.1 fastICA_1.2-2 munsell_0.5.0 GenomeInfoDbData_1.2.2
[175] DO.db_2.9 GetoptLong_0.1.8 iterators_1.0.12 reshape2_1.4.3 gtable_0.3.0 Seurat_3.2.2
LS0tCnRpdGxlOiAiVGhlIHJlc3VsdHMgZm9yIG1vbm9jeXRlcyBkYXRhc2V0IgpzdWJ0aXRsZTogInJhdyBjb3VudCBtYXRyaXgsIENhckRFQywgRENBK2NvbWJhdCwgc2NWSSBhbmQgc2Nhbm9yYW1hIgphdXRob3I6ICBYaWFuZ2ppZSBMaQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclbS8lZC8lWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICBqZWt5bGx0aGF0OjpqZWt5bGxkb3duOgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIHByZXR0eWRvYzo6aHRtbF9wcmV0dHk6CiAgICB0aGVtZTogY2F5bWFuCiAgICBoaWdobGlnaHQ6IGdpdGh1YgogICAgbWF0aDoga2F0ZXgKICAgIHRvYzogeWVzCi0tLQoKPHN0eWxlPgpwcmUgewogIG1heC1oZWlnaHQ6IDIwMHB4OwogIGZsb2F0OiBsZWZ0OwogIHdpZHRoOiA5MTBweDsKICBvdmVyZmxvdy15OiBhdXRvOwp9CnByZS5yIHsKICBtYXgtaGVpZ2h0OiBub25lOwp9Cjwvc3R5bGU+CgoKKipEYXRhIFN1bW1hcnk6KiogCgpUaGlzIGRhdGFzZXQgd2FzIGdlbmVyYXRlZCBieSBvdXIgZ3JvdXAsIHdoaWNoIGNhbiBiZSBkb3dubG9hZGVkIGZyb20gW0dFTyAoR1NFMTQ2OTc0KV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9nZW8vcXVlcnkvYWNjLmNnaT9hY2M9R1NFMTQ2OTc0KSBvciBvciBbaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xa1I4SGh1Zm9vMmgyT3RvbVc4bjNrTTBnYVFoVlM1NjQvdmlldz91c3A9c2hhcmluZ10oaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xa1I4SGh1Zm9vMmgyT3RvbVc4bjNrTTBnYVFoVlM1NjQvdmlldz91c3A9c2hhcmluZykuIFRoaXMgZGF0YXNldCB3YXMgZ2VuZXJhdGVkIGZyb20gaHVtYW4gcGVyaXBoZXJhbCBibG9vZCBtb25vbnVjbGVhciBjbGVhciBjZWxscyBieSBGaWNvbGwgU2VwYXJhdGlvbiBmb2xsb3dlZCBieSBDRDE0IGFuZCBDRDE2IHBvc2l0aXZlIGNlbGwgc2VsZWN0aW9uLiBTaW5jZSB0aGUgQ0QxNCBhbmQgQ0QxNiBhbnRpYm9kaWVzIGFyZSBub3QgMTAwJSBzcGVjaWZpYywgc29tZSBUIGNlbGxzIHdlcmUgYWxzbyBwcmVzZW50IGluIHRoZSBzY1JOQS1zZXEgZGF0YS4gV2UgcGVyZm9ybWVkIGNsdXN0ZXJpbmcgYW5hbHlzaXMgdXNpbmcgbGVpZGVu4oCZcyBhbGdvcml0aG0gZm9yIGVhY2ggYmF0Y2ggYW5kIGlkZW50aWZpZWQgMjg4IFQgY2VsbHMgaW4gdG90YWwgYmFzZWQgb24gdGhlIFQgY2VsbCBtYXJrZXIgZ2VuZXMgQ0QzRCwgQ0QzRSBhbmQgQ0QzRy4gQWZ0ZXJpbmcgcmVtb3ZpbmcgdGhlc2UgMjg4IFQgY2VsbHMsIHRoZXJlIGFyZSAxMCw4NzggY2VsbHMgYW5kIDIxLDI4OSBnZW5lcywgd2hpY2ggd2FzIHByb2Nlc3NlZCBhbmQgc2VxdWVuY2VkIGF0IHRocmVlIGRpZmZlcmVudCBkYXlzLCByZXN1bHRpbmcgaW4gdGhyZWUgYmF0Y2hlcyAoMyw2NDAgY2VsbHMgaW4gVDEsIDQsODMzIGNlbGxzIGluIFQyIGFuZCAyLDQwNSBjZWxscyBpbiBUMykgbGVmdCBpbiB0aGUgcmVtYWluaW5nIGFuYWx5c2lzLiAKCl9fKioqSHVtYW4gbW9ub2N5dGUgcHJlcGFyYXRpb24qKipfXzogTW9ub2N5dGUgcHJlcGFyYXRpb24gdXNlcyBhIG1vZGlmaWNhdGlvbiBvZiBwdWJsaXNoZWQgcHJvdG9jb2xzLiBCcmllZmx5LCB+MjAgbWwgYmxvb2QgZHJhd24gaW4gc29kaXVtIGhlcGFyaW4gd2FzIHByb2Nlc3NlZCBpbW1lZGlhdGVseSBpbiB0aGUgbGFiIGluIHRoZSBDbGluaWNhbCBSZXNlYXJjaCBDZW50ZXIgYXQgQ29sdW1iaWEgVW5pdmVyc2l0eS4gUEJNQ3Mgd2VyZSBpc29sYXRlZCBieSBncmFkaWVudCBGaWNvbGwgcGFxdWUgY2VudHJpZnVnYXRpb24sIHdoaWNoIG1haW50YWlucyBjZWxsIHZpYWJpbGl0eSBhbmQgcHJldmVudHMgZXggdml2byBhY3RpdmF0aW9uIGR1cmluZyBjZWxsIHJlY292ZXJ5LiBDZWxscyB3ZXJlIHN0YWluZWQgd2l0aCBhbnRpYm9kaWVzIGFnYWluc3QgaHVtYW4gSExBRFIsIENEMTQgYW5kIENEMTYgYW5kIG1vbm9jeXRlIHN1YnNldHMgZGVmaW5lZCBhcyBITEFEUitDRDE0KytDRDE2LShjbGFzc2ljYWwpLCBITEFEUitDRDE0KytDRDE2KyAoaW50ZXJtZWRpYXRlKSwgSExBRFIrQ0QxNGRpbS9DRDE2KysgKG5vbmNsYXNzaWNhbCwgcGF0cm9sbGluZyBtb25vY3l0ZSkuIERBUEkgc3RhaW5pbmcgd2FzIHVzZWQgdG8gZXhjbHVkZSBkZWFkIGNlbGxzLiBNb25vY3l0ZXMgd2VyZSBzb3J0ZWQgYnkgYSBCRCBJbmZsdXggU29ydGVyIGludG8gdHViZXMgZm9yIHJlYWwtdGltZSAxMHggR2Vub21pY3MgYW5hbHlzaXMuCgojIFN1bW1hcnkgCgpIZXJlIEkgdXNlZCBtb25vY2xlMyAobW9ub2NsZTNfMC4yLjEpIHRvIGNvbmR1Y3QgdGhlIHBzZXVkb3RpbWUgYW5hbHlzaXMuIAoKPiA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj4gQ2FyREVDLCBzY1ZJIGFuZCBEQ0EgYXJlIGJvdGggZGVlcCBsZWFybmluZyBiYXNlZCBtZXRob2RzLiBGb3IgZWFjaCBtZXRob2QsIHdlIHVzZWQgYWxsIGdlbmVzIGFzIHRoZSBpbnB1dCwgdGhlIHdheSBvZiBgVXNpbmcgbGF0ZXRuYE9uZSBpcyB0aGUgc3RhbmRhcmQgcGlwbGluZSBmb3IgbW9ub2NsZTMgKGBkZW5vc2llZCBjb3VudGAgLT4gYG5vcm1hbGl6YXRpb25gIC0+IGBzY2FsaW5nYCAtPiBgcGNhYCBkaW1lbnNpb24gcmVkdWN0aW9uIC0+IGB1bWFwIHZpc3VhbGl6YXRpb25gIGJhc2VkIG9uIGBwY2FgIGRpbWVuc2lvbiByZWR1Y3Rpb24pIGFuZCB0aGUgb3RoZXIgbWV0aG9kIHJlcGxjZXMgdGhlIGBwY2FgIGJ5IHRoZSBsYXRlbnQgcmVwcmVzZW50YXRpb24gYW5kIHRoZW4gdW1hcCB2aXN1YWxpemF0aW9uIGJhc2VkIG9uIGxhdGVudCByZXByZXNlbnRhdGlvbi4gPC9zcGFuPgoKCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgotIF9fKioqSFZHcyByYXcqKipfXzogT25seSB1c2luZyBoaWdobHkgdmFyaWFibGUgZ2VuZXMgKEhWRykgYXMgdGhlIGlucHV0cyBmb3IgTW9ub2NsZTMKLSBfXyoqKkFsbCBnZW5lcyByYXcqKipfXzogVXNpbmcgYWxsIGdlbmVzIChIVkcpIGFzIHRoZSBpbnB1dHMgZm9yIE1vbm9jbGUzCi0gX18qKipVc2luZyBsYXRlbnQqKipfXzogUmVwbGNlaW5nIHRoZSBgcGNhYCBieSB0aGUgbGF0ZW50IHJlcHJlc2VudGF0aW9uIGFuZCB0aGVuIHVtYXAgdmlzdWFsaXphdGlvbiBiYXNlZCBvbiBsYXRlbnQgcmVwcmVzZW50YXRpb24gKENhckRFQywgRENBK2NvbWJhdCwgc2NWSSBhbmQgc2Nhbm9yYW1hKS4KLSBfXyoqKkhWRyBkZW5vaXNlZCoqKl9fOiBPbmx5IHVzaW5nIGRlbm9zaW5lZCBleHByZXNzaW9uIGNvdW50IGZyb20gdGhvc2UgaGlnaGx5IHZhcmlhYmxlIGdlbmVzIChIVkdzKSBhcyB0aGUgaW5wdXQgZm9yIG1vbm9jbGUzIGFuZCB0aGVuIGNvbmR1Y3RlZCBzdGFuZGFyZCBwaXBsaW5lIG9mIG1vbm9jbGUzIChDYXJERUMsIERDQSwgc2NWSSBhbmQgc2Nhbm9yYW1hKS4KLSBfXyoqKkFsbCBnZW5lcyBkZW5vaXNlZCoqKl9fOiBVc2VkIGFsbCBkZW5vaXNlZCBleHByZXNzaW9uIHZhbHVlcyBhcyB0aGUgaW5wdXQgZm9yIG1vbm9jbGUzIGFuZCB0aGVuIGNvbmR1Y3RlZCB0aGUgc3RhbmRhcmQgcGlwbGluZSBvZiBtb25vY2xlMyAoQ2FyREVDLCBEQ0EsIGFuZCBzY1ZJKS4KCmBgYHtyfQpvcHRpb25zKHdhcm49LTEpICMgdHVybiBvZmYgd2FybmluZyBtZXNzYWdlIGdsb2JhbGx5Ci5saWJQYXRocyhjKCIvaG9tZS94aWFveGlhbmcvUi94ODZfNjQtcGMtbGludXgtZ251LWxpYnJhcnkvMy41IiwubGliUGF0aHMoKSkpClN5cy5zZXRlbnYoUkVUSUNVTEFURV9QWVRIT05fRU5WPSIvaG9tZS94aWFveGlhbmcvYW5hY29uZGEzL2VudnMvcHkzNiIpIz0iL2hvbWUveGlhb3hpYW5nLy5jb25kYS9lbnZzL0RFU0NWSVIiClN5cy5zZXRlbnYoUkVUSUNVTEFURV9QWVRIT049Ii91c3IvYmluL3B5dGhvbjMiKQojUkVUSUNVTEFURV9QWVRIT049Ii9ob21lL3hpYW94aWFuZy9hbmFjb25kYTMvYmluL3B5dGhvbjMiLAppZiAoIlNldXJhdCIgJWluJSBsb2FkZWROYW1lc3BhY2VzKCkpIGRldGFjaCgicGFja2FnZTpTZXVyYXQiLHVubG9hZCA9IFQpCmR5bi5sb2FkKCIvaG9tZS94aWFveGlhbmcvUi94ODZfNjQtcGMtbGludXgtZ251LWxpYnJhcnkvMy41L3NmL2xpYnMvc2Yuc28iKQojc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkobW9ub2NsZSxsaWIubG9jID0gIi91c3IvbGliL1IvbW9ub2NsZV9hbHBoYSIpKSMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCIiKQojZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJjb2xlLXRyYXBuZWxsLWxhYi9ERFJUcmVlIiwgcmVmPSJzaW1wbGUtcHB0LWxpa2UiLGxpYj0iL3Vzci9saWIvUi9tb25vY2xlX2FscGhhIikKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigici1zcGF0aWFsL3NmIikgaWYgCiNpbnN0YWxsLnBhY2thZ2VzKCJ+L0Rvd25sb2Fkcy9tb25vY2xlLXJlbGVhc2UtbW9ub2NsZTNfYWxwaGEvIiwgcmVwb3MgPSBOVUxMLGxpYiA9ICIvdXNyL2xpYi9SL21vbm9jbGVfYWxwaGEiKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShyZXRpY3VsYXRlKSkKI3N1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGRldnRvb2xzKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkobW9ub2NsZTMpKQoKI3N1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGZsZXhjbHVzdCkpCiNzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShtY2NsdXN0KSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoZHBseXIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShnZ2pveSkpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KFZHQU0pKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShrbml0cikpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGdncGxvdDIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShrYWJsZUV4dHJhKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoY293cGxvdCkpCiNweV9pbnN0YWxsKCd1bWFwLWxlYXJuJywgcGlwID0gVCwgcGlwX2lnbm9yZV9pbnN0YWxsZWQgPSBUKQojaW1wb3J0KCJsZWlkZW4iKQojZmlnX3BhdGg9Ii9ob21lL3hpYW94aWFuZy9Eb2N1bWVudHMvREVTQ19wYXBlcl9wcmVwYXJlL0RFU0NfcGFwZXJfZmluYWwvZm9ybWFsX3JldmlzZWQvZmlndXJlc19zZXAvIgpkYXRhZGlycGF0aD0iLi8iCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVQpCmBgYAoKCmBgYHtyfQpkZl9wc2V1ZG90aW1lX2xpc3Q9bGlzdCgpCmBgYAoKYGBge3IsZWNobz1GLGluY2x1ZGU9VCxldmFsPVR9CmdldF9wX25ldyA9ZnVuY3Rpb24oeCx4Mj1OVUxMKSB7CiByZXMxPXNhcHBseSh4LGZ1bmN0aW9uKGkwKSBpZmVsc2UoaTA8PTAsIjwyLjJlLTE2IixzY2FsZXM6OnNjaWVudGlmaWMoaTAsZGlnaXRzID0gMykpKSAKIHJlczI9cmVwKGMoIiIpLGxlbmd0aD1sZW5ndGgocmVzMSkpCiBpZighaXMubnVsbCh4MikpewogICByZXMyPXJvdW5kKHgyLDMpIAogfQogcmV0dXJuKHBhc3RlMChyZXMyLCIgKCIscmVzMSwiKSIpKQp9CgpudW1fbWV0aG9kcz0xNiNvcmlnaW5hbCAxMwpTdGFibGU1PWRhdGEuZnJhbWUoTWV0aG9kPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIiksCiAgICAgICAgICAgICAgICAgIGBUMSB2LnMuIFQyYD1yZXAoIjwyLjJlLTE2IixsZW5ndGg9bnVtX21ldGhvZHMpLAogICAgICAgICAgICAgICAgICBgVDEgdi5zLiBUM2A9cmVwKCI8Mi4yZS0xNiIsbGVuZ3RoPW51bV9tZXRob2RzKSwKICAgICAgICAgICAgICAgICAgYFQyIHYucy4gVDNgPXJlcCgiPDIuMmUtMTYiLGxlbmd0aD1udW1fbWV0aG9kcyksc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnJvd25hbWVzKFN0YWJsZTUpPVN0YWJsZTUkTWV0aG9kCiN0YWJsZTUgJT4lCiMgIGthYmxlKCkgJT4lCiMgIGthYmxlX3N0eWxpbmcoKQpgYGAKCgpgYGB7cn0KIyBsb2FkIG5lY2Vzc2F5IGZ1bmN0aW9uCiNzb3VyY2UoIi9tZWRpYS94aWFveGlhbmcvRC9ERVNDX3JlcHJvZHVjaWJsZV9maWxlL2hlbHBmdW5jX25ldy5SIikKI3NvdXJjZSgiL21lZGlhL3hpYW94aWFuZy9EL1VwZW5uX2NvbXB1dGVyX2JhY2t1cC9Eb2N1bWVudHMvSHVtYW5fSGVhcnRfUHJvamVjdC9oZWFydC9IZWFydF9yZXN1bHRfdXBkYXRlZC9oZWxwZnVuY19uZXcuUiIpCm9sZD10aGVtZV9zZXQodGhlbWVfYncoKSt0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9IndoaXRlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQgPWVsZW1lbnRfYmxhbmsoKSkpCgpCYXRjaEtMPWZ1bmN0aW9uKGRmLGRpbWVuc2lvbkRhdGE9TlVMTCxyZXBsaWNhdGVzPTIwMCxuX25laWdoYm9ycz0xMDAsbl9jZWxscz0xMDAsYmF0Y2g9IkJhdGNoSUQiKXsKICAjZW50cm9weSBvZiBiYXRjaCBtaXhpaW5nCiAgI3JlcGxpY2F0ZXMgaXMgdGhlIG51bWJlciBvZiBib29zdHJhcCB0aW1lcwogICNuX25laWdoYm9ycyBpcyB0aGUgbnVtYmVyIG9mIG5lYXJlc3QgbmVpZ2hib3VycyBvZiBjZWxsKGZyb20gYWxsIGJhdGNocykKICAjbl9jZWxscyBpcyB0aGUgbnVtYmVyIG9mIHJhbmRvbWx5IHBpY2tlZCBjZWxscwogIGlmIChpcy5udWxsKGRpbWVuc2lvbkRhdGEpKXsKICAgICAgICB0c25lZGF0YT1hcy5tYXRyaXgoZGZbLGMoInRTTkVfMSIsInRTTkVfMiIpXSkKICB9ZWxzZXsKICAgICAgICB0c25lZGF0YT1hcy5tYXRyaXgoZGltZW5zaW9uRGF0YSkKICB9CiAgYmF0Y2hkYXRhPWZhY3Rvcihhcy52ZWN0b3IoZGZbLGJhdGNoXSkpCiAgdGFibGUuYmF0Y2hkYXRhPWFzLm1hdHJpeCh0YWJsZShiYXRjaGRhdGEpKVssMV0KICB0bXAwMD10YWJsZS5iYXRjaGRhdGEvc3VtKHRhYmxlLmJhdGNoZGF0YSkjcHJvcG9ydGF0aW9uIG9mIHBvcHVsYXRpb24KICBuPWRpbShkZilbMV0KICBLTD1zYXBwbHkoMTpyZXBsaWNhdGVzLGZ1bmN0aW9uKHgpewogICAgYm9vdHNhbXBsZXM9c2FtcGxlKDE6bixuX2NlbGxzKQogICAgI25lYXJlc3Q9bm4yKHRzbmVkYXRhLHRzbmVkYXRhW2Jvb3RzYW1wbGVzLF0saz1uX25laWdoYm9ycykKICAgIG5lYXJlc3Q9bmFib3I6Omtubih0c25lZGF0YSx0c25lZGF0YVtib290c2FtcGxlcyxdLGs9bWluKDUqbGVuZ3RoKHRtcDAwKSxuX25laWdoYm9ycykpCiAgICBLTF94PXNhcHBseSgxOmxlbmd0aChib290c2FtcGxlcyksZnVuY3Rpb24oeSl7CiAgICAgIGlkPW5lYXJlc3Qkbm4uaWR4W3ksXQogICAgICB0bXA9YXMubWF0cml4KHRhYmxlKGJhdGNoZGF0YVtpZF0pKVssMV0KICAgICAgdG1wPXRtcC9zdW0odG1wKQogICAgICByZXR1cm4oc3VtKHRtcCpsb2cyKHRtcC90bXAwMCksbmEucm0gPSBUKSkKICAgIH0pCiAgICByZXR1cm4obWVhbihLTF94LG5hLnJtID0gVCkpCiAgfSkKICByZXR1cm4oS0wpCn0KYGBgCgpgYGB7cn0KQ29udmVydF90b19zZXVyYXQzPWZ1bmN0aW9uKGFkYXRhKXsKICBzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSgiU2V1cmF0IixsaWIubG9jID0gIi91c3IvbGliL1Ivc2VsZl9saWJyYXJ5LyIpKQogIG10eD1weV90b19yKGFkYXRhJFgkVCR0b2NzYygpKQogIGNlbGxpbmZvPXB5X3RvX3IoYWRhdGEkb2JzKQogIGdlbmVpbmZvPXB5X3RvX3IoYWRhdGEkdmFyKQogIGNvbG5hbWVzKG10eCk9Y2VsbGluZm8kY2VsbG5hbWUKICByb3duYW1lcyhtdHgpPXJvd25hbWVzKGdlbmVpbmZvKQogIG9iaj1DcmVhdGVTZXVyYXRPYmplY3QobXR4LG1ldGEuZGF0YSA9IGNlbGxpbmZvWywhY29sbmFtZXMoY2VsbGluZm8pJWluJWMoIm5fZ2VuZXMiLCJuX2NvdW50cyIpLGRyb3A9Rl0sbWluLmZlYXR1cmVzICA9IDEpCiAgcmV0dXJuKG9iaikKfQpnZXR3ZCgpCmBgYAoKCmBgYHtyfQpnZXRfcGxvdDQ9ZnVuY3Rpb24oZGYwMCl7CiAgcDE9Z2dwbG90KCkrZ2VvbV9wb2ludChkYXRhID1kZjAwLGFlcyh4PVVNQVBfMSx5PVVNQVBfMixjb2xvcj1GQ0dSM0EpLHNpemU9MC4wMSkrCiAgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3c9ImdyZXkiLGhpZ2g9InJlZCIpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpKwogICAgZ3VpZGVzKGNvbG9yPWd1aWRlX2NvbG9yYmFyKHRpdGxlLnZqdXN0ID0gMC43KSkKICAKICBwMj1nZ3Bsb3QoKStnZW9tX3BvaW50KGRhdGEgPWRmMDAsYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGNvbG9yPVMxMDBBOCksc2l6ZT0wLjAxKSsKICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iZ3JleSIsaGlnaD0icmVkIikrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikrCiAgICAgZ3VpZGVzKGNvbG9yPWd1aWRlX2NvbG9yYmFyKHRpdGxlLnZqdXN0ID0gMC43KSkKICAKICBwMz1nZ3Bsb3QoZGF0YSA9ZGYwMCxhZXMoeD1wc2V1ZG90aW1lLHk9RkNHUjNBKSkrCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPUJhdGNoSUQpLHNpemU9MC4wMSkrCiAgICAgIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUpKSkrCiAgICAgIGdlb21fc21vb3RoKGFlcyhjb2xvcj1CYXRjaElEKSxtZXRob2Q9ImdhbSIsZm9ybXVsYSA9IHkgfiBzKHgsIGJzPSJjcyIpKSsKICAgICAgIGdlb21fc21vb3RoKGNvbG9yPSJibGFjayIsbWV0aG9kPSJnYW0iLGZvcm11bGEgPSB5IH4gcyh4LCBicz0iY3MiKSxzaXplPTAuNSkrCiAgICAgIGdndGl0bGUoIiIpK3hsYWIoIlBzZXVkb3RpbWUiKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJib2xkIixoanVzdD0wLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSxmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDEsMCwwKSwiY20iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKICAKICBwND1nZ3Bsb3QoZGF0YSA9ZGYwMCxhZXMoeD1wc2V1ZG90aW1lLHk9UzEwMEE4KSkrCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPUJhdGNoSUQpLHNpemU9MC4wMSkrCiAgICAgIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUpKSkrCiAgICAgIGdlb21fc21vb3RoKGFlcyhjb2xvcj1CYXRjaElEKSxtZXRob2Q9ImdhbSIsZm9ybXVsYSA9IHkgfiBzKHgsIGJzPSJjcyIpKSsKICAgICAgIGdlb21fc21vb3RoKGNvbG9yPSJibGFjayIsbWV0aG9kPSJnYW0iLGZvcm11bGEgPSB5IH4gcyh4LCBicz0iY3MiKSxzaXplPTAuNSkrCiAgICAgIGdndGl0bGUoIiIpK3hsYWIoIlBzZXVkb3RpbWUiKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJib2xkIixoanVzdD0wLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSxmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpK3NjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDIiKQogIAogIHA9ZWdnOjpnZ2FycmFuZ2UocDEscDMscDIscDQsbmNvbD00LGRyYXc9RikKICByZXR1cm4ocCkKfQoKZ2V0X3Bsb3Q0X3NlcD1mdW5jdGlvbihkZjAwKXsKICBwMT1nZ3Bsb3QoKStnZW9tX3BvaW50KGRhdGEgPWRmMDAsYWVzKHg9VU1BUF8xLHk9VU1BUF8yLGNvbG9yPUZDR1IzQSksc2l6ZT0wLjAxKSsKICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iZ3JleSIsaGlnaD0icmVkIikrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikrCiAgICBndWlkZXMoY29sb3I9Z3VpZGVfY29sb3JiYXIodGl0bGUudmp1c3QgPSAwLjcpKQogIAogIHAyPWdncGxvdCgpK2dlb21fcG9pbnQoZGF0YSA9ZGYwMCxhZXMoeD1VTUFQXzEseT1VTUFQXzIsY29sb3I9UzEwMEE4KSxzaXplPTAuMDEpKwogICAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93PSJncmV5IixoaWdoPSJyZWQiKSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSsKICAgICBndWlkZXMoY29sb3I9Z3VpZGVfY29sb3JiYXIodGl0bGUudmp1c3QgPSAwLjcpKQogIAogIHAzPWdncGxvdChkYXRhID1kZjAwLGFlcyh4PXBzZXVkb3RpbWUseT1GQ0dSM0EpKSsKICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9QmF0Y2hJRCksc2l6ZT0wLjA1KSsKICAgICAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NSkpKSsKICAgICAgZ2VvbV9zbW9vdGgoYWVzKGNvbG9yPUJhdGNoSUQpLG1ldGhvZD0iZ2FtIixmb3JtdWxhID0geSB+IHMoeCwgYnM9ImNzIikpKwogICAgICAgZ2VvbV9zbW9vdGgoY29sb3I9ImJsYWNrIixtZXRob2Q9ImdhbSIsZm9ybXVsYSA9IHkgfiBzKHgsIGJzPSJjcyIpLHNpemU9MC41KSsKICAgICAgZ2d0aXRsZSgiIikreGxhYigiUHNldWRvdGltZSIpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE4LGZhY2U9ImJvbGQiLGhqdXN0PTAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE1LGZhY2U9ImJvbGQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDEsMCwwKSwiY20iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKICBwND1nZ3Bsb3QoZGF0YSA9ZGYwMCxhZXMoeD1wc2V1ZG90aW1lLHk9UzEwMEE4KSkrCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPUJhdGNoSUQpLHNpemU9MC4wNSkrCiAgICAgIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUpKSkrCiAgICAgIGdlb21fc21vb3RoKGFlcyhjb2xvcj1CYXRjaElEKSxtZXRob2Q9ImdhbSIsZm9ybXVsYSA9IHkgfiBzKHgsIGJzPSJjcyIpKSsKICAgICAgIGdlb21fc21vb3RoKGNvbG9yPSJibGFjayIsbWV0aG9kPSJnYW0iLGZvcm11bGEgPSB5IH4gcyh4LCBicz0iY3MiKSxzaXplPTAuNSkrCiAgICAgIGdndGl0bGUoIiIpK3hsYWIoIlBzZXVkb3RpbWUiKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJib2xkIixoanVzdD0wLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSxmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpCiAgcmV0dXJuKGxpc3QocDEscDIscDMscDQpKQp9CgpgYGAKCgoKCmBgYHtyfQphZD1pbXBvcnQoImFubmRhdGEiLGNvbnZlcnQgPSBGQUxTRSkKYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi8uLi9kY2FfdGVzdC5oNWFkIikKb2JqMD1Db252ZXJ0X3RvX3NldXJhdDMoYWRhdGEpCm9iajA9Tm9ybWFsaXplRGF0YShvYmowLHZlcmJvc2UgPSBGKQpyYXcuZGF0YT1vYmowQGFzc2F5cyRSTkFAY291bnRzCmBgYAoKYGBge3J9Cm1hcHJ1bGVzPWMoIjIwMTdfMDgwMSI9IlQxIiwiMjAxN18xMDE3Ij0iVDIiLCIyMDE3XzExMjAiPSJUMyIpCm1hcHJ1bGVzCmBgYAoKSGVyZSB3ZSBjb21wYXJlZCBkaWZmZXJlbnQgbWV0aG9kcywgaW5jbHVkaW5nIGBEQ0FgIGFuZCBgc2NWSWAuIAoKYGBge3J9Cmh2Z19nZW5lcz1yZWFkLnRhYmxlKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9DYXJERUNfaHZnX3VzZWQudHN2IixoZWFkZXIgPSBULHNlcD0iXHQiLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpodmdfZ2VuZXM9c3Vic2V0KGh2Z19nZW5lcyxWYXJpYW5jZS5UeXBlPT0iSFZHIikgI3RvcCAyMDAwIGdlbmVzIApgYGAKCiMgTW9ub2NsZTMgZm9yIGByYXcgZGF0YWAKIyMgSFZHcyByYXcgCgpgYGB7cn0KY2VsbC5tZXRhLmRhdGE9b2JqMEBtZXRhLmRhdGEKY2VsbC5tZXRhLmRhdGEkZGF0YXNldF9iYXRjaD1wbHlyOjptYXB2YWx1ZXMoY2VsbC5tZXRhLmRhdGEkYmF0Y2hfbGFiZWwsbmFtZXMobWFwcnVsZXMpLG1hcHJ1bGVzKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKHJhdy5kYXRhKSkscm93Lm5hbWVzID0gbWFrZS51bmlxdWUocm93bmFtZXMocmF3LmRhdGEpKSkKI3BkIDwtIG5ldygiQW5ub3RhdGVkRGF0YUZyYW1lIixkYXRhPWNlbGwubWV0YS5kYXRhKQojZmQgPC0gbmV3KCJBbm5vdGF0ZWREYXRhRnJhbWUiLGRhdGE9Z2VuZV9hbm4pCmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChyYXcuZGF0YVtyb3duYW1lcyhyYXcuZGF0YSklaW4laHZnX2dlbmVzJGdlbmVuYW1lLF0sIAogICAgICAgICAgICAgICAgICAgICAgICAgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9tZXRhZGF0YSA9Z2VuZV9hbm5bZ2VuZV9hbm4kZ2VuZV9zaG9ydF9uYW1lJWluJWh2Z19nZW5lcyRnZW5lbmFtZSwsZHJvcD1GXSkKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyBhIGhlbHBlciBmdW5jdGlvbiB0byBpZGVudGlmeSB0aGUgcm9vdCBwcmluY2lwYWwgcG9pbnRzOgpnZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUgPC0gZnVuY3Rpb24oY2RzLCBjbHVzdGVyPWMoIjEiLCI1IikpewogIHJvb3RfcHJfbm9kZXM9c2FwcGx5KGNsdXN0ZXIsZnVuY3Rpb24oaWkpewogICAgY2VsbF9pZHMgPC0gd2hpY2goY29sRGF0YShjZHMpWywgImNsdXN0ZXJzIl0gJWluJWlpKQogIAogIGNsb3Nlc3RfdmVydGV4IDwtY2RzQHByaW5jaXBhbF9ncmFwaF9hdXhbWyJVTUFQIl1dJHByX2dyYXBoX2NlbGxfcHJval9jbG9zZXN0X3ZlcnRleAogIAogIGNsb3Nlc3RfdmVydGV4IDwtIGFzLm1hdHJpeChjbG9zZXN0X3ZlcnRleFtjb2xuYW1lcyhjZHMpLCBdKQogIHJvb3RfcHJfbm9kZXMgPC1pZ3JhcGg6OlYocHJpbmNpcGFsX2dyYXBoKGNkcylbWyJVTUFQIl1dKSRuYW1lW2FzLm51bWVyaWMobmFtZXMod2hpY2gubWF4KHRhYmxlKGNsb3Nlc3RfdmVydGV4W2NlbGxfaWRzLF0pKSkpXQogIH0pCiAgcm9vdF9wcl9ub2Rlcwp9CiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjEiLCIzIiwiNCIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLHJvb3RfcHJfbm9kZXMgPSBpZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpjb2xEYXRhKGNkcykkcHNldWRvdGltZT1wc2V1ZG90aW1lKGNkcykKY29sRGF0YShjZHMpJFBzZXVkb3RpbWU9Y29sRGF0YShjZHMpJHBzZXVkb3RpbWUvbWF4KGNvbERhdGEoY2RzKSRwc2V1ZG90aW1lLG5hLnJtID0gVCkKZGZfZGVuPXBEYXRhKGNkcylbLGMoIlBzZXVkb3RpbWUiLCJkYXRhc2V0X2JhdGNoIildCmRmX2Rlbj1hcy5kYXRhLmZyYW1lKGRmX2RlblshaXMuaW5maW5pdGUoZGZfZGVuJFBzZXVkb3RpbWUpLF0pCgpzZXQuc2VlZCgxMCkKdGhlbWVfdXNlPXRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKcF9vcmlfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIixncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKICAgICAgICAgIApwX29yaV8yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfb3JpXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9vcmk9ZWdnOjpnZ2FycmFuZ2UocF9vcmlfMSxwX29yaV8yLHBfb3JpXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7cn0KIyBwcmludGVkIGhvdyBtYW55IGNlbGxzIHdpdGggbm8gcHNldWRvdGltZQp0YWJsZShhcy5udW1lcmljKGlzLmluZmluaXRlKHBEYXRhKGNkcylbLGMoInBzZXVkb3RpbWUiKV0pKSkgIzAgbWVhbiBub3JtYWwgcHNldWRvdGltZSBhbmQgMSBtZWFucyBpbmZpbml0eS4KYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwX21vbm9jbGVfb3JpCmBgYAoKYGBge3J9CmNkc19leHBycz1GZXRjaERhdGEob2JqMCx2YXJzID0gYygiRkNHUjNBIiwiUzEwMEE4IikpCmRmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCiNjZHNfZXhwcnM9YXMubWF0cml4KFNpbmdsZUNlbGxFeHBlcmltZW50Ojpjb3VudHMoY2RzKVtjKCJGQ0dSM0EiLCJTMTAwQTgiKSxdKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsbG9nMXAodChjZHNfZXhwcnMpL3NpemVfZmFjdG9ycyhjZHMpKSkpCmRmMCRVTUFQXzE9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywxXQpkZjAkVU1BUF8yPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMl0KZGYwJEJhdGNoSUQ9cERhdGEoY2RzKSRkYXRhc2V0X2JhdGNoCmRmMD1kZjBbaXMuZmluaXRlKGRmMCRwc2V1ZG90aW1lKSxdCmRmMD1kZjBbb3JkZXIoZGYwJHBzZXVkb3RpbWUsZGVjcmVhc2luZyA9IEYpLCxkcm9wPUZdCmRmMCR4PWRmMCRwc2V1ZG90aW1lL21heChkZjAkcHNldWRvdGltZSkKZGZfcHNldWRvdGltZV9saXN0JHJhdz1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCgp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzEsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKIyMgQWxsIGdlbmVzIHJhdyAKYGBge3J9CmNlbGwubWV0YS5kYXRhPW9iajBAbWV0YS5kYXRhCmNlbGwubWV0YS5kYXRhJGRhdGFzZXRfYmF0Y2g9cGx5cjo6bWFwdmFsdWVzKGNlbGwubWV0YS5kYXRhJGJhdGNoX2xhYmVsLG5hbWVzKG1hcHJ1bGVzKSxtYXBydWxlcykKZ2VuZV9hbm49ZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhyYXcuZGF0YSkpLHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKHJhdy5kYXRhKSkpCiNwZCA8LSBuZXcoIkFubm90YXRlZERhdGFGcmFtZSIsZGF0YT1jZWxsLm1ldGEuZGF0YSkKI2ZkIDwtIG5ldygiQW5ub3RhdGVkRGF0YUZyYW1lIixkYXRhPWdlbmVfYW5uKQpjZHMgPC0gbmV3X2NlbGxfZGF0YV9zZXQocmF3LmRhdGEsIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubikKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgYSBoZWxwZXIgZnVuY3Rpb24gdG8gaWRlbnRpZnkgdGhlIHJvb3QgcHJpbmNpcGFsIHBvaW50czoKZ2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlIDwtIGZ1bmN0aW9uKGNkcywgY2x1c3Rlcj1jKCIxIiwiNSIpKXsKICByb290X3ByX25vZGVzPXNhcHBseShjbHVzdGVyLGZ1bmN0aW9uKGlpKXsKICAgIGNlbGxfaWRzIDwtIHdoaWNoKGNvbERhdGEoY2RzKVssICJjbHVzdGVycyJdICVpbiVpaSkKICAKICBjbG9zZXN0X3ZlcnRleCA8LWNkc0BwcmluY2lwYWxfZ3JhcGhfYXV4W1siVU1BUCJdXSRwcl9ncmFwaF9jZWxsX3Byb2pfY2xvc2VzdF92ZXJ0ZXgKICAKICBjbG9zZXN0X3ZlcnRleCA8LSBhcy5tYXRyaXgoY2xvc2VzdF92ZXJ0ZXhbY29sbmFtZXMoY2RzKSwgXSkKICByb290X3ByX25vZGVzIDwtaWdyYXBoOjpWKHByaW5jaXBhbF9ncmFwaChjZHMpW1siVU1BUCJdXSkkbmFtZVthcy5udW1lcmljKG5hbWVzKHdoaWNoLm1heCh0YWJsZShjbG9zZXN0X3ZlcnRleFtjZWxsX2lkcyxdKSkpKV0KICB9KQogIHJvb3RfcHJfbm9kZXMKfQojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCI0IiwiNSIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLHJvb3RfcHJfbm9kZXMgPSBpZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpjb2xEYXRhKGNkcykkcHNldWRvdGltZT1wc2V1ZG90aW1lKGNkcykKY29sRGF0YShjZHMpJFBzZXVkb3RpbWU9Y29sRGF0YShjZHMpJHBzZXVkb3RpbWUvbWF4KGNvbERhdGEoY2RzKSRwc2V1ZG90aW1lLG5hLnJtID0gVCkKZGZfZGVuPXBEYXRhKGNkcylbLGMoIlBzZXVkb3RpbWUiLCJkYXRhc2V0X2JhdGNoIildCmRmX2Rlbj1hcy5kYXRhLmZyYW1lKGRmX2RlblshaXMuaW5maW5pdGUoZGZfZGVuJFBzZXVkb3RpbWUpLF0pCgpzZXQuc2VlZCgxMCkKdGhlbWVfdXNlPXRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKcF9vcmlfYWxsXzE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSt0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCiAgICAgICAgICAKcF9vcmlfYWxsXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9vcmlfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9vcmlfYWxsPWVnZzo6Z2dhcnJhbmdlKHBfb3JpX2FsbF8xLHBfb3JpX2FsbF8yLHBfb3JpX2FsbF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3J9CiMgcHJpbnRlZCBob3cgbWFueSBjZWxscyB3aXRoIG5vIHBzZXVkb3RpbWUKdGFibGUoYXMubnVtZXJpYyhpcy5pbmZpbml0ZShwRGF0YShjZHMpWyxjKCJwc2V1ZG90aW1lIildKSkpICMwIG1lYW4gbm9ybWFsIHBzZXVkb3RpbWUgYW5kIDEgbWVhbnMgaW5maW5pdHkuCmBgYAoKYGBge3IgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX29yaV9hbGwKYGBgCgpgYGB7cn0KY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKI2Nkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxsb2cxcCh0KGNkc19leHBycykvc2l6ZV9mYWN0b3JzKGNkcykpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkcmF3X2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVsyLDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCiMgTW9ub2NsZTMgdXNpbmcgY2FyREVDCgpJbiB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgZXZhbHV0YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBjYXJERUMuIAoKTm90ZSB0aGF0OiBjYXJERUMgdXNlZCBhbGwgZ2VuZXMgYW5kIGV4dHJhY3RlZCBIVkcgdG8gZXZhbHVhdGUuCgpgYGB7cn0KYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9DYXJERUMgUmVzdWx0cy9hZGF0YV9DYXJERUMuaDVhZCIpCmBgYAoKYGBge3J9CmNlbGwubWV0YS5kYXRhPXB5X3RvX3IoYWRhdGEkb2JzKQpjZWxsLm1ldGEuZGF0YSRkYXRhc2V0X2JhdGNoPXBseXI6Om1hcHZhbHVlcyhjZWxsLm1ldGEuZGF0YSRiYXRjaF9sYWJlbCxuYW1lcyhtYXBydWxlcyksbWFwcnVsZXMpCmdlbmVfYW5uMD1weV90b19yKGFkYXRhJHZhcikKZ2VuZV9hbm49ZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhnZW5lX2FubjApKSwKICAgICAgICAgICAgICAgICAgICBWYXJpYW5jZVR5cGU9Z2VuZV9hbm4wJGBWYXJpYW5jZSBUeXBlYCwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhnZW5lX2FubjApKSkKbXR4PXQocHlfdG9fcihhZGF0YSRsYXllcnNbJ2Rlbm9pc2VkIGNvdW50cyddKSkKY29sbmFtZXMobXR4KT1jZWxsLm1ldGEuZGF0YSRjZWxsbmFtZQpyb3duYW1lcyhtdHgpPXJvd25hbWVzKGdlbmVfYW5uKQptdHhfc2l6ZWZhY3Rvcj0xZTQvY29sU3VtcyhtdHgpCmBgYAoKCiMjIFVzaW5nIGxhdGVudCAKCmBgYHtyfQpjZHMgPC0gbmV3X2NlbGxfZGF0YV9zZXQobXR4LCBjZWxsX21ldGFkYXRhID0gY2VsbC5tZXRhLmRhdGEsZ2VuZV9tZXRhZGF0YSA9Z2VuZV9hbm4pCiMjIFN0ZXAgMTogTm9ybWFsaXplIGFuZCBwcmUtcHJvY2VzcyB0aGUgZGF0YQpjZHMgPC0gcHJlcHJvY2Vzc19jZHMoY2RzLCBudW1fZGltID0gMzIsbWV0aG9kPSJQQ0EiLG5vcm1fbWV0aG9kPSJsb2ciLHZlcmJvc2UgPSBGKQoKdG1wMD1weV90b19yKGFkYXRhJG9ic21bImVtYmVkZGluZyJdKQpjb2xuYW1lcyh0bXAwKT1wYXN0ZTAoIlBDIiwxOm5jb2wodG1wMCkpCnJlZHVjZWREaW1zKGNkcykkUENBPXRtcDAKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCIzIikpCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXM9aWRzKQpwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfY2FyREVDX2xhdGVudF8xPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXRfYmF0Y2giLCxncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgICAgICAgICAKcF9jYXJERUNfbGF0ZW50XzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9jYXJERUNfbGF0ZW50XzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9jYXJERUNfbGF0ZW50PWVnZzo6Z2dhcnJhbmdlKHBfY2FyREVDX2xhdGVudF8xLHBfY2FyREVDX2xhdGVudF8yLHBfY2FyREVDX2xhdGVudF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwX21vbm9jbGVfY2FyREVDX2xhdGVudApgYGAKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpPTFlNC9yb3dTdW1zKG10eCkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsbG9nMXAodChjZHNfZXhwcnMpKm10eF9zaXplZmFjdG9yKSkpCmRmMCRVTUFQXzE9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywxXQpkZjAkVU1BUF8yPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMl0KZGYwJEJhdGNoSUQ9cERhdGEoY2RzKSRkYXRhc2V0X2JhdGNoCmRmMD1kZjBbaXMuZmluaXRlKGRmMCRwc2V1ZG90aW1lKSxdCmRmMD1kZjBbb3JkZXIoZGYwJHBzZXVkb3RpbWUsZGVjcmVhc2luZyA9IEYpLCxkcm9wPUZdCmRmMCR4PWRmMCRwc2V1ZG90aW1lL21heChkZjAkcHNldWRvdGltZSkKZGZfcHNldWRvdGltZV9saXN0JGNhckRFQ19sYXRlbnQ9ZGYwCmBgYAoKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVszLDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCgojIyBIVkdzIGRlbm9pc2VkCgpgYGB7cn0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0sIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubltnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLCxkcm9wPUZdKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIikKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjQiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfY2FyREVDX2Rlbm9pc2VkX2h2Z18xID0gcGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsLGdyYXBoX2xhYmVsX3NpemU9MCxhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNywgc2l6ZT01KSkpKwogIHRoZW1lX3VzZSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKICAgICAgICAgIApwX2NhckRFQ19kZW5vaXNlZF9odmdfMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJQc2V1ZG90aW1lIixsYWJlbF9icmFuY2hfcG9pbnRzPVQsZ3JhcGhfbGFiZWxfc2l6ZT0yLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gMC4yKSwKICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChhbmdsZT0tNTAgKSwKICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuNSwiY20iKSwKICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMSwiY20iKSkrCiAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG91cmJhcihsYWJlbC5wb3NpdGlvbiA9ICJ0b3AiKSkrdGhlbWVfdXNlCgpwX2NhckRFQ19kZW5vaXNlZF9odmdfMz1nZ3Bsb3QoZGF0YT1kZl9kZW4pK2dlb21fZGVuc2l0eShhZXMoeD1Qc2V1ZG90aW1lLGZpbGw9ZGF0YXNldF9iYXRjaCksYWxwaGE9MC43KSsKICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpK3RoZW1lX3VzZQoKcF9tb25vY2xlX2NhckRFQ19kZW5vaXNlZF9odmc9ZWdnOjpnZ2FycmFuZ2UocF9jYXJERUNfZGVub2lzZWRfaHZnXzEscF9jYXJERUNfZGVub2lzZWRfaHZnXzIscF9jYXJERUNfZGVub2lzZWRfaHZnXzMsbmNvbD0zLGRyYXc9RikKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9jYXJERUNfZGVub2lzZWRfaHZnCmBgYAoKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCmRmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGxvZzFwKHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRjYXJERUNfZGVub2lzZWRfaHZnPWRmMApgYGAKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVs0LDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCiMjIEFsbCBnZW5lcyBkZW5vaXNlZAoKYGBge3J9CmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHgsIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubikKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDI6IFJlbW92ZSBiYXRjaCBlZmZlY3RzIHdpdGggY2VsbCBhbGlnbm1lbnQKIyNjZHMgPC0gYWxpZ25fY2RzKGNkcywgYWxpZ25tZW50X2dyb3VwID0gIkJhdGNoSUQiLCByZXNpZHVhbF9tb2RlbF9mb3JtdWxhX3N0ciA9IE5VTEwpCiMjIFN0ZXAgMzogUmVkdWNlIHRoZSBkaW1lbnNpb25zIHVzaW5nIFVNQVAKY2RzIDwtIHJlZHVjZV9kaW1lbnNpb24oY2RzLHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIscHJlcHJvY2Vzc19tZXRob2Q9IlBDQSIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDQ6IENsdXN0ZXIgdGhlIGNlbGxzCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0iVU1BUCIsY2x1c3Rlcl9tZXRob2QgPSAibGVpZGVuIix2ZXJib3NlID0gRikKCiMgQ29uc3RydWN0IHRoZSBncmFwaAojIE5vdGUgdGhhdCwgZm9yIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIHJ1biwgdGhlIGdyYXBoIHNob3VsZCBiZSBmdWxseSAocGFydGlvbmx5KSBjb25uZWN0ZWQKIyMgU3RlcCA1OiBMZWFybiBhIGdyYXBoCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBULHZlcmJvc2UgPSBGKQpjb2xEYXRhKGNkcykkY2x1c3RlcnM9Y2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMKcDE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicGFydGl0aW9uIixsYWJlbF9jZWxsX2dyb3VwcyA9IEYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVycyIsbGFiZWxfY2VsbF9ncm91cHM9RixncmFwaF9sYWJlbF9zaXplPTIsIGxhYmVsX2xlYXZlcz1GLGxhYmVsX2JyYW5jaF9wb2ludHM9RikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnA9Y293cGxvdDo6cGxvdF9ncmlkKHAxLHAyLGFsaWduID0gImgiLG5jb2wgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiNCIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzPWlkcykKI3Bsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiKQpgYGAKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXBzZXVkb3RpbWUoY2RzKQpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX2NhckRFQ19kZW5vaXNlZF9hbGxfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfY2FyREVDX2Rlbm9pc2VkX2FsbF8yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfY2FyREVDX2Rlbm9pc2VkX2FsbF8zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfY2FyREVDX2Rlbm9pc2VkX2FsbD1lZ2c6OmdnYXJyYW5nZShwX2NhckRFQ19kZW5vaXNlZF9hbGxfMSxwX2NhckRFQ19kZW5vaXNlZF9hbGxfMixwX2NhckRFQ19kZW5vaXNlZF9hbGxfMyxuY29sPTMsZHJhdz1GKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX2NhckRFQ19kZW5vaXNlZF9hbGwKYGBgCgpgYGB7cn0KI2Nkc19leHBycz1GZXRjaERhdGEob2JqMCx2YXJzID0gYygiRkNHUjNBIiwiUzEwMEE4IikpCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxjZHNfZXhwcnMpKQpjZHNfZXhwcnM9YXMubWF0cml4KFNpbmdsZUNlbGxFeHBlcmltZW50Ojpjb3VudHMoY2RzKVtjKCJGQ0dSM0EiLCJTMTAwQTgiKSxdKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxsb2cxcCh0KGNkc19leHBycykqbXR4X3NpemVmYWN0b3IpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkY2FyREVDX2Rlbm9pc2VkX2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbNSwyOjRdPW1hdHJpeChnZXRfcF9uZXcoYyh0dDEkcC52YWx1ZSx0dDIkcC52YWx1ZSx0dDMkcC52YWx1ZSksYyh0dDEkc3RhdGlzdGljLHR0MiRzdGF0aXN0aWMsdHQzJHN0YXRpc3RpYykpLDEsMykKYGBgCgojIE1vbm9jbGUzIHVzaW5nIHNjVkkKCmBgYHtyfQojYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9zY1ZJIFJlc3VsdHMvbW9ub2N5dGVzX0FMTC9hZGF0YV9hbGwuaDVhZCIpCmFkYXRhPWFkJHJlYWRfaDVhZCgiLi4vZmluYWxfcHJvY2Vzc2VkX3Jlc3VsdHMvc2NWSSBSZXN1bHRzIE5ldy9tb25vY3l0ZXNfQUxML2FkYXRhX2FsbC5oNWFkIikKYGBgCgpgYGB7cn0KY2VsbC5tZXRhLmRhdGE9cHlfdG9fcihhZGF0YSRvYnMpCmNlbGwubWV0YS5kYXRhJGRhdGFzZXRfYmF0Y2g9cGx5cjo6bWFwdmFsdWVzKGNlbGwubWV0YS5kYXRhJGJhdGNoX2xhYmVsLG5hbWVzKG1hcHJ1bGVzKSxtYXBydWxlcykKZ2VuZV9hbm4wPXB5X3RvX3IoYWRhdGEkdmFyKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpKQptdHg9dChweV90b19yKGFkYXRhJFgpKQpjb2xuYW1lcyhtdHgpPWNlbGwubWV0YS5kYXRhJGNlbGxuYW1lCnJvd25hbWVzKG10eCk9cm93bmFtZXMoZ2VuZV9hbm4pCm10eF9zaXplZmFjdG9yPTFlNC9jb2xTdW1zKG10eCkKYGBgCgojIyBVc2luZyBsYXRlbnQKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIix2ZXJib3NlID0gRikKdG1wMD1weV90b19yKGFkYXRhJG9ic21bIlhfbGF0ZW50Il0pCmNvbG5hbWVzKHRtcDApPXBhc3RlMCgiUEMiLDE6bmNvbCh0bXAwKSkKcmVkdWNlZERpbXMoY2RzKSRQQ0E9dG1wMAoKIyMgU3RlcCAyOiBSZW1vdmUgYmF0Y2ggZWZmZWN0cyB3aXRoIGNlbGwgYWxpZ25tZW50CiMjY2RzIDwtIGFsaWduX2NkcyhjZHMsIGFsaWdubWVudF9ncm91cCA9ICJCYXRjaElEIiwgcmVzaWR1YWxfbW9kZWxfZm9ybXVsYV9zdHIgPSBOVUxMKQojIyBTdGVwIDM6IFJlZHVjZSB0aGUgZGltZW5zaW9ucyB1c2luZyBVTUFQCmNkcyA8LSByZWR1Y2VfZGltZW5zaW9uKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiLHByZXByb2Nlc3NfbWV0aG9kPSJQQ0EiLHZlcmJvc2UgPSBGKQoKIyMgU3RlcCA0OiBDbHVzdGVyIHRoZSBjZWxscwpjZHMgPC0gY2x1c3Rlcl9jZWxscyhjZHMscmVkdWN0aW9uX21ldGhvZCA9IlVNQVAiLGNsdXN0ZXJfbWV0aG9kID0gImxlaWRlbiIsdmVyYm9zZSA9IEYpCgojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjMiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCiNzYXZlUkRTKGNkcyxmaWxlID0gImNkc19zY3ZpLnJkcyIpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfc2NWSV9sYXRlbnRfYWxsXzE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsLGdyYXBoX2xhYmVsX3NpemU9MCxhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNywgc2l6ZT01KSkpKwogIHRoZW1lX3VzZSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKICAgICAgICAgIApwX3NjVklfbGF0ZW50X2FsbF8yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfc2NWSV9sYXRlbnRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9zY1ZJX2xhdGVudF9hbGw9ZWdnOjpnZ2FycmFuZ2UocF9zY1ZJX2xhdGVudF9hbGxfMSxwX3NjVklfbGF0ZW50X2FsbF8yLHBfc2NWSV9sYXRlbnRfYWxsXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX3NjVklfbGF0ZW50X2FsbApgYGAKCgoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGxvZzFwKHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSx0KGNkc19leHBycykpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRzY1ZJX2xhdGVudF9hbGw9ZGYwCmBgYAoKLSBGZWF0dXJlIHBsb3RzIG9mIGBGQ0dSM0FgIGFuZCBgUzEwMEE4YAoKYGBge3J9CnA9Z2V0X3Bsb3Q0KGRmMDAgPSBkZjApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzYsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKCiMjIEhWR3MgZGVub2lzZWQKCgpgYGB7cn0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eFtyb3duYW1lcyhtdHgpJWluJWh2Z19nZW5lcyRnZW5lbmFtZSxdLCBjZWxsX21ldGFkYXRhID0gY2VsbC5tZXRhLmRhdGEsZ2VuZV9tZXRhZGF0YSA9Z2VuZV9hbm5bZ2VuZV9hbm4kZ2VuZV9zaG9ydF9uYW1lJWluJWh2Z19nZW5lcyRnZW5lbmFtZSwsZHJvcD1GXSkKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDI6IFJlbW92ZSBiYXRjaCBlZmZlY3RzIHdpdGggY2VsbCBhbGlnbm1lbnQKIyNjZHMgPC0gYWxpZ25fY2RzKGNkcywgYWxpZ25tZW50X2dyb3VwID0gIkJhdGNoSUQiLCByZXNpZHVhbF9tb2RlbF9mb3JtdWxhX3N0ciA9IE5VTEwpCiMjIFN0ZXAgMzogUmVkdWNlIHRoZSBkaW1lbnNpb25zIHVzaW5nIFVNQVAKY2RzIDwtIHJlZHVjZV9kaW1lbnNpb24oY2RzLHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIscHJlcHJvY2Vzc19tZXRob2Q9IlBDQSIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDQ6IENsdXN0ZXIgdGhlIGNlbGxzCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0iVU1BUCIsY2x1c3Rlcl9tZXRob2QgPSAibGVpZGVuIix2ZXJib3NlID0gRikKCiMgQ29uc3RydWN0IHRoZSBncmFwaAojIE5vdGUgdGhhdCwgZm9yIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIHJ1biwgdGhlIGdyYXBoIHNob3VsZCBiZSBmdWxseSAocGFydGlvbmx5KSBjb25uZWN0ZWQKIyMgU3RlcCA1OiBMZWFybiBhIGdyYXBoCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBULHZlcmJvc2UgPSBGKQpjb2xEYXRhKGNkcykkY2x1c3RlcnM9Y2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMKcDE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicGFydGl0aW9uIixsYWJlbF9jZWxsX2dyb3VwcyA9IEYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVycyIsbGFiZWxfY2VsbF9ncm91cHM9RixncmFwaF9sYWJlbF9zaXplPTIsIGxhYmVsX2xlYXZlcz1GLGxhYmVsX2JyYW5jaF9wb2ludHM9RikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnA9Y293cGxvdDo6cGxvdF9ncmlkKHAxLHAyLGFsaWduID0gImgiLG5jb2wgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiMyIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzPWlkcykKI3Bsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiKQpgYGAKCgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpjb2xEYXRhKGNkcykkcHNldWRvdGltZT1wc2V1ZG90aW1lKGNkcykKY29sRGF0YShjZHMpJFBzZXVkb3RpbWU9Y29sRGF0YShjZHMpJHBzZXVkb3RpbWUvbWF4KGNvbERhdGEoY2RzKSRwc2V1ZG90aW1lLG5hLnJtID0gVCkKZGZfZGVuPXBEYXRhKGNkcylbLGMoIlBzZXVkb3RpbWUiLCJkYXRhc2V0X2JhdGNoIildCmRmX2Rlbj1hcy5kYXRhLmZyYW1lKGRmX2RlblshaXMuaW5maW5pdGUoZGZfZGVuJFBzZXVkb3RpbWUpLF0pCnNldC5zZWVkKDEwKQoKdGhlbWVfdXNlPXRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKcF9zY3ZpX2Rlbm9pc2VkX2h2Z18xPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXRfYmF0Y2giLCxncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgICAgICAgICAKcF9zY3ZpX2Rlbm9pc2VkX2h2Z18yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfc2N2aV9kZW5vaXNlZF9odmdfMz1nZ3Bsb3QoZGF0YT1kZl9kZW4pK2dlb21fZGVuc2l0eShhZXMoeD1Qc2V1ZG90aW1lLGZpbGw9ZGF0YXNldF9iYXRjaCksYWxwaGE9MC43KSsKICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpK3RoZW1lX3VzZQoKcF9tb25vY2xlX3NjdmlfZGVub2lzZWRfaHZnPWVnZzo6Z2dhcnJhbmdlKHBfc2N2aV9kZW5vaXNlZF9odmdfMSxwX3NjdmlfZGVub2lzZWRfaHZnXzIscF9zY3ZpX2Rlbm9pc2VkX2h2Z18zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9zY3ZpX2Rlbm9pc2VkX2h2ZwpgYGAKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxsb2cxcCh0KGNkc19leHBycykqbXR4X3NpemVmYWN0b3IpKSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3Qkc2NWSV9kZW5vc2llZF9odmc9ZGYwCmBgYAoKLSBGZWF0dXJlIHBsb3RzIG9mIGBGQ0dSM0FgIGFuZCBgUzEwMEE4YAoKYGBge3J9CnA9Z2V0X3Bsb3Q0KGRmMDAgPSBkZjApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzcsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKIyMgQWxsIGdlbmVzIGRlbm9pc2VkCgpgYGB7cn0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCIzIikpCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXM9aWRzKQojcGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIpCmBgYAoKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CngwPXBzZXVkb3RpbWUoY2RzKQp4MFtpcy5pbmZpbml0ZSh4MCldPU5BCmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXgwCgpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX3NjVklfZGVub2lzZWRfYWxsXzE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsLGdyYXBoX2xhYmVsX3NpemU9MCxhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNywgc2l6ZT01KSkpKwogIHRoZW1lX3VzZSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKICAgICAgICAgIApwX3NjVklfZGVub2lzZWRfYWxsXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9zY1ZJX2Rlbm9pc2VkX2FsbF8zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfc2NWSV9kZW5vaXNlZF9hbGw9ZWdnOjpnZ2FycmFuZ2UocF9zY1ZJX2Rlbm9pc2VkX2FsbF8xLHBfc2NWSV9kZW5vaXNlZF9hbGxfMixwX3NjVklfZGVub2lzZWRfYWxsXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwX21vbm9jbGVfc2NWSV9kZW5vaXNlZF9hbGwKYGBgCgoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGxvZzFwKHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSx0KGNkc19leHBycykpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRzY1ZJX2Rlbm9zaWVkX2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbOCwyOjRdPW1hdHJpeChnZXRfcF9uZXcoYyh0dDEkcC52YWx1ZSx0dDIkcC52YWx1ZSx0dDMkcC52YWx1ZSksYyh0dDEkc3RhdGlzdGljLHR0MiRzdGF0aXN0aWMsdHQzJHN0YXRpc3RpYykpLDEsMykKYGBgCgojIE1vbm9jbGUzIHVzaW5nIGRjYStjb21iYXQKCmBgYHtyfQojYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9kY2EgUmVzdWx0cy9hZGF0YV9hbGwuaDVhZCIpCmFkYXRhPWFkJHJlYWRfaDVhZCgiLi4vZmluYWxfcHJvY2Vzc2VkX3Jlc3VsdHMvZGNhIFJlc3VsdHMgTmV3L2FkYXRhX2FsbC5oNWFkIikKYGBgCgpgYGB7cn0KY2VsbC5tZXRhLmRhdGE9cHlfdG9fcihhZGF0YSRvYnMpCmNlbGwubWV0YS5kYXRhJGRhdGFzZXRfYmF0Y2g9cGx5cjo6bWFwdmFsdWVzKGNlbGwubWV0YS5kYXRhJGJhdGNoX2xhYmVsLG5hbWVzKG1hcHJ1bGVzKSxtYXBydWxlcykKZ2VuZV9hbm4wPXB5X3RvX3IoYWRhdGEkdmFyKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpKQptdHg9dChweV90b19yKGFkYXRhJFgpKQpjb2xuYW1lcyhtdHgpPWNlbGwubWV0YS5kYXRhJGNlbGxuYW1lCnJvd25hbWVzKG10eCk9cm93bmFtZXMoZ2VuZV9hbm4pCm10eF9zaXplZmFjdG9yPTFlNC9jb2xTdW1zKG10eCkKYGBgCgojIyBVc2luZyBjb21iYXRlZCBsYXRlbnQgZnJvbSBkY2EKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIikKCnRtcDA9cHlfdG9fcihhZGF0YSRvYnNtWyJYX2RjYV9sYXRlbnQiXSkgI29yaWdpbmFsIGRjYQpjb2xuYW1lcyh0bXAwKT1wYXN0ZTAoIlBDIiwxOm5jb2wodG1wMCkpCnJlZHVjZWREaW1zKGNkcykkUENBPXRtcDAKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjQiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCiNzYXZlUkRTKGNkcyxmaWxlPSJjZHNfZGNhLnJkcyIpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfZGNhX2xhdGVudF9hbGxfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfZGNhX2xhdGVudF9hbGxfMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJQc2V1ZG90aW1lIixsYWJlbF9icmFuY2hfcG9pbnRzPVQsZ3JhcGhfbGFiZWxfc2l6ZT0yLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gMC4yKSwKICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChhbmdsZT0tNTAgKSwKICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuNSwiY20iKSwKICAgICAgICAgICAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMSwiY20iKSkrCiAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG91cmJhcihsYWJlbC5wb3NpdGlvbiA9ICJ0b3AiKSkrdGhlbWVfdXNlCgpwX2RjYV9sYXRlbnRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9kY2FfbGF0ZW50X2FsbD1lZ2c6OmdnYXJyYW5nZShwX2RjYV9sYXRlbnRfYWxsXzEscF9kY2FfbGF0ZW50X2FsbF8yLHBfZGNhX2xhdGVudF9hbGxfMyxuY29sPTMsZHJhdz1GKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9kY2FfbGF0ZW50X2FsbApgYGAKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxsb2cxcCh0KGNkc19leHBycykqbXR4X3NpemVmYWN0b3IpKSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkZGNhX2xhdGVudF9hbGw9ZGYwCmBgYAoKLSBGZWF0dXJlIHBsb3RzIG9mIGBGQ0dSM0FgIGFuZCBgUzEwMEE4YAoKYGBge3J9CnA9Z2V0X3Bsb3Q0KGRmMDAgPSBkZjApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzksMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKIyMgSFZHcyBkZW5vaXNlZAoKYGBge3J9CmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHhbcm93bmFtZXMobXR4KSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsXSwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uW2dlbmVfYW5uJGdlbmVfc2hvcnRfbmFtZSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsLGRyb3A9Rl0pCiMjIFN0ZXAgMTogTm9ybWFsaXplIGFuZCBwcmUtcHJvY2VzcyB0aGUgZGF0YQpjZHMgPC0gcHJlcHJvY2Vzc19jZHMoY2RzLCBudW1fZGltID0gMzIsbWV0aG9kPSJQQ0EiLG5vcm1fbWV0aG9kPSJsb2ciLHZlcmJvc2UgPSBGKQoKdG1wMD1weV90b19yKGFkYXRhJG9ic21bIlhfcGNhaHZnIl0pICNvcmlnaW5hbCBkY2EKY29sbmFtZXModG1wMCk9cGFzdGUwKCJQQyIsMTpuY29sKHRtcDApKQpyZWR1Y2VkRGltcyhjZHMpJFBDQT10bXAwCgoKIyMgU3RlcCAyOiBSZW1vdmUgYmF0Y2ggZWZmZWN0cyB3aXRoIGNlbGwgYWxpZ25tZW50CiMjY2RzIDwtIGFsaWduX2NkcyhjZHMsIGFsaWdubWVudF9ncm91cCA9ICJCYXRjaElEIiwgcmVzaWR1YWxfbW9kZWxfZm9ybXVsYV9zdHIgPSBOVUxMKQojIyBTdGVwIDM6IFJlZHVjZSB0aGUgZGltZW5zaW9ucyB1c2luZyBVTUFQCmNkcyA8LSByZWR1Y2VfZGltZW5zaW9uKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiLHByZXByb2Nlc3NfbWV0aG9kPSJQQ0EiLHZlcmJvc2UgPSBGKQoKIyMgU3RlcCA0OiBDbHVzdGVyIHRoZSBjZWxscwpjZHMgPC0gY2x1c3Rlcl9jZWxscyhjZHMscmVkdWN0aW9uX21ldGhvZCA9IlVNQVAiLGNsdXN0ZXJfbWV0aG9kID0gImxlaWRlbiIsdmVyYm9zZSA9IEYpCgojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiMSIsIjMiLCI0IikpCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXM9aWRzKQojcGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIpCmBgYAoKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXBzZXVkb3RpbWUoY2RzKQpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX2RjYV9kZW5vaXNlZF9odmdfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfZGNhX2Rlbm9pc2VkX2h2Z18yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfZGNhX2Rlbm9pc2VkX2h2Z18zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfZGNhX2Rlbm9pc2VkX2h2Zz1lZ2c6OmdnYXJyYW5nZShwX2RjYV9kZW5vaXNlZF9odmdfMSxwX2RjYV9kZW5vaXNlZF9odmdfMixwX2RjYV9kZW5vaXNlZF9odmdfMyxuY29sPTMsZHJhdz1GKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9kY2FfZGVub2lzZWRfaHZnCmBgYAoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkZGNhX2Rlbm9pc2VkX2h2Zz1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbMTAsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKIyMgQWxsIGdlbmVzIGRlbm9pc2VkCgpgYGB7cn0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIix2ZXJib3NlID0gRikKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIix2ZXJib3NlID0gRikKCnRtcDA9cHlfdG9fcihhZGF0YSRvYnNtWyJYX3BjYWFsbCJdKSAjb3JpZ2luYWwgZGNhCmNvbG5hbWVzKHRtcDApPXBhc3RlMCgiUEMiLDE6bmNvbCh0bXAwKSkKcmVkdWNlZERpbXMoY2RzKSRQQ0E9dG1wMAoKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iLHZlcmJvc2UgPSBGKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCIyIiwiNCIsIjUiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfZGNhX2Rlbm9pc2VkX2FsbF8xPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXRfYmF0Y2giLCxncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgICAgICAgICAKcF9kY2FfZGVub2lzZWRfYWxsXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9kY2FfZGVub2lzZWRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9kY2FfZGVub2lzZWRfYWxsPWVnZzo6Z2dhcnJhbmdlKHBfZGNhX2Rlbm9pc2VkX2FsbF8xLHBfZGNhX2Rlbm9pc2VkX2FsbF8yLHBfZGNhX2Rlbm9pc2VkX2FsbF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9kY2FfZGVub2lzZWRfYWxsCmBgYAoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGxvZzFwKHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSx0KGNkc19leHBycykpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRkY2FfZGVub2lzZWRfYWxsPWRmMApgYGAKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVsxMSwyOjRdPW1hdHJpeChnZXRfcF9uZXcoYyh0dDEkcC52YWx1ZSx0dDIkcC52YWx1ZSx0dDMkcC52YWx1ZSksYyh0dDEkc3RhdGlzdGljLHR0MiRzdGF0aXN0aWMsdHQzJHN0YXRpc3RpYykpLDEsMykKYGBgCgoKIyBNb25vY2xlMyB1c2luZyBNTk4KCmBgYHtyfQpvdXRwdXQ9cmVhZFJEUygiLi4vZmluYWxfcHJvY2Vzc2VkX3Jlc3VsdHMvTU5OX2NvcnJlY3RlZF9hbGwucmRzIikKbXR4PW91dHB1dEBhc3NheXMkZGF0YSRjb3JyZWN0ZWQKY2VsbC5tZXRhLmRhdGE9Y29sRGF0YShvdXRwdXQpCmNlbGwubWV0YS5kYXRhJGRhdGFzZXRfYmF0Y2g9cGx5cjo6bWFwdmFsdWVzKGNlbGwubWV0YS5kYXRhJGJhdGNoX2xhYmVsLG5hbWVzKG1hcHJ1bGVzKSxtYXBydWxlcykKZ2VuZV9hbm49ZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhtdHgpKSwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBtYWtlLnVuaXF1ZShyb3duYW1lcyhtdHgpKSkKCmBgYAoKIyMjIEhWR3MgZGVub2lzZWQKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eFtyb3duYW1lcyhtdHgpJWluJWh2Z19nZW5lcyRnZW5lbmFtZSxdLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uW2dlbmVfYW5uJGdlbmVfc2hvcnRfbmFtZSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsLGRyb3A9Rl0pCiMjIFN0ZXAKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMixtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIpCiN0bXAwPXB5X3RvX3IoYWRhdGEkb2JzbVsiWF9kY2FfbGF0ZW50Il0pCiNjb2xuYW1lcyh0bXAwKT1wYXN0ZTAoIlBDIiwxOm5jb2wodG1wMCkpCiNyZWR1Y2VkRGltcyhjZHMpJFBDQT10bXAwCgojIyBTdGVwIDI6IFJlbW92ZSBiYXRjaCBlZmZlY3RzIHdpdGggY2VsbCBhbGlnbm1lbnQKIyNjZHMgPC0gYWxpZ25fY2RzKGNkcywgYWxpZ25tZW50X2dyb3VwID0gIkJhdGNoSUQiLCByZXNpZHVhbF9tb2RlbF9mb3JtdWxhX3N0ciA9IE5VTEwpCiMjIFN0ZXAgMzogUmVkdWNlIHRoZSBkaW1lbnNpb25zIHVzaW5nIFVNQVAKY2RzIDwtIHJlZHVjZV9kaW1lbnNpb24oY2RzLHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIscHJlcHJvY2Vzc19tZXRob2Q9IlBDQSIpCgojIyBTdGVwIDQ6IENsdXN0ZXIgdGhlIGNlbGxzCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0iVU1BUCIsY2x1c3Rlcl9tZXRob2QgPSAibGVpZGVuIikKCiMgQ29uc3RydWN0IHRoZSBncmFwaAojIE5vdGUgdGhhdCwgZm9yIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIHJ1biwgdGhlIGdyYXBoIHNob3VsZCBiZSBmdWxseSAocGFydGlvbmx5KSBjb25uZWN0ZWQKIyMgU3RlcCA1OiBMZWFybiBhIGdyYXBoCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBULHZlcmJvc2UgPSBGKQpjb2xEYXRhKGNkcykkY2x1c3RlcnM9Y2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMKcDE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicGFydGl0aW9uIixsYWJlbF9jZWxsX2dyb3VwcyA9IEYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVycyIsbGFiZWxfY2VsbF9ncm91cHM9RixncmFwaF9sYWJlbF9zaXplPTIsIGxhYmVsX2xlYXZlcz1GLGxhYmVsX2JyYW5jaF9wb2ludHM9RikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnA9Y293cGxvdDo6cGxvdF9ncmlkKHAxLHAyLGFsaWduID0gImgiLG5jb2wgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiMiIsIjMiLCI0IikpCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXM9aWRzKQojcGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIpCmBgYAoKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXBzZXVkb3RpbWUoY2RzKQpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQojc2F2ZVJEUyhjZHMsZmlsZT0iY2RzX21ubi5yZHMiKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX21ubl9kZW5vaXNlZF9odmdfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfbW5uX2Rlbm9pc2VkX2h2Z18yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfbW5uX2Rlbm9pc2VkX2h2Z18zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfbW5uX2Rlbm9pc2VkX2h2Zz1lZ2c6OmdnYXJyYW5nZShwX21ubl9kZW5vaXNlZF9odmdfMSxwX21ubl9kZW5vaXNlZF9odmdfMixwX21ubl9kZW5vaXNlZF9odmdfMyxuY29sPTMsZHJhdz1GKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwX21vbm9jbGVfbW5uX2Rlbm9pc2VkX2h2ZwpgYGAKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCmRmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLHQoY2RzX2V4cHJzKSptdHhfc2l6ZWZhY3RvcikpCmRmMCRVTUFQXzE9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywxXQpkZjAkVU1BUF8yPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMl0KZGYwJEJhdGNoSUQ9cERhdGEoY2RzKSRkYXRhc2V0X2JhdGNoCmRmMD1kZjBbaXMuZmluaXRlKGRmMCRwc2V1ZG90aW1lKSxdCmRmMD1kZjBbb3JkZXIoZGYwJHBzZXVkb3RpbWUsZGVjcmVhc2luZyA9IEYpLCxkcm9wPUZdCmRmMCR4PWRmMCRwc2V1ZG90aW1lL21heChkZjAkcHNldWRvdGltZSkKZGZfcHNldWRvdGltZV9saXN0JG1ubl9kZW5vaXNlZF9odmc9ZGYwCmBgYAoKLSBGZWF0dXJlIHBsb3RzIG9mIGBGQ0dSM0FgIGFuZCBgUzEwMEE4YAoKYGBge3J9CnA9Z2V0X3Bsb3Q0KGRmMDAgPSBkZjApCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzEyLDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCgojIyMgQWxsIGdlbmVzIGRlbm9pc2VkCgpgYGB7cn0Kb3V0cHV0PXJlYWRSRFMoIi4uL2ZpbmFsX3Byb2Nlc3NlZF9yZXN1bHRzL01OTl9jb3JyZWN0ZWRfYWxsLnJkcyIpCm10eD1vdXRwdXRAYXNzYXlzJGRhdGEkY29ycmVjdGVkCgpjZWxsLm1ldGEuZGF0YT1jb2xEYXRhKG91dHB1dCkKY2VsbC5tZXRhLmRhdGEkZGF0YXNldF9iYXRjaD1wbHlyOjptYXB2YWx1ZXMoY2VsbC5tZXRhLmRhdGEkYmF0Y2hfbGFiZWwsbmFtZXMobWFwcnVsZXMpLG1hcHJ1bGVzKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKG10eCkpLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKG10eCkpKQoKI2NvbG5hbWVzKG10eCk9Y29sRGF0YShvdXRwdXQpJGNlbGxuYW1lCiNyb3duYW1lcyhtdHgpPXJvd25hbWVzKGdlbmVfYW5uKQojbXR4X3NpemVmYWN0b3I9MWU0L2NvbFN1bXMobXR4KQpgYGAKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDMyLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIikKI3RtcDA9cHlfdG9fcihhZGF0YSRvYnNtWyJYX2RjYV9sYXRlbnQiXSkKI2NvbG5hbWVzKHRtcDApPXBhc3RlMCgiUEMiLDE6bmNvbCh0bXAwKSkKI3JlZHVjZWREaW1zKGNkcykkUENBPXRtcDAKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCI2IiwiMyIsIjUiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfbW5uX2Rlbm9pc2VkX2FsbF8xPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXRfYmF0Y2giLCxncmFwaF9sYWJlbF9zaXplPTAsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYT0wLjcsIHNpemU9NSkpKSsKICB0aGVtZV91c2UrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCiAgICAgICAgICAKcF9tbm5fZGVub2lzZWRfYWxsXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9tbm5fZGVub2lzZWRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9tbm5fZGVub2lzZWRfYWxsPWVnZzo6Z2dhcnJhbmdlKHBfbW5uX2Rlbm9pc2VkX2FsbF8xLHBfbW5uX2Rlbm9pc2VkX2FsbF8yLHBfbW5uX2Rlbm9pc2VkX2FsbF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9tbm5fZGVub2lzZWRfYWxsCmBgYAoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKm10eF9zaXplZmFjdG9yKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3QkbW5uX2Rlbm9pc2VkX2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbMTMsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKCgoKIyBNb25vY2xlMyB1c2luZyBzY2Fub3JhbWEKCgpgYGB7cn0KYWRhdGE9YWQkcmVhZF9oNWFkKCIuLi9maW5hbF9wcm9jZXNzZWRfcmVzdWx0cy9zY2Fub3JhbWEgUmVzdWx0cy9hZGF0YV9BTEwuaDVhZCIpIwpgYGAKCmBgYHtyfQpjZWxsLm1ldGEuZGF0YT1weV90b19yKGFkYXRhJG9icykKY2VsbC5tZXRhLmRhdGEkZGF0YXNldF9iYXRjaD1wbHlyOjptYXB2YWx1ZXMoY2VsbC5tZXRhLmRhdGEkYmF0Y2hfbGFiZWwsbmFtZXMobWFwcnVsZXMpLG1hcHJ1bGVzKQpnZW5lX2FubjA9cHlfdG9fcihhZGF0YSRyYXckdmFyKQpnZW5lX2Fubj1kYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1ha2UudW5pcXVlKHJvd25hbWVzKGdlbmVfYW5uMCkpKQptdHg9dChweV90b19yKGFkYXRhJFgkdG9jc2MoKSkpI2FkYXRhJHJhdwpjb2xuYW1lcyhtdHgpPWNlbGwubWV0YS5kYXRhJGNlbGxuYW1lCnJvd25hbWVzKG10eCk9cm93bmFtZXMoZ2VuZV9hbm4pCm10eF9zaXplZmFjdG9yPTFlNC9jb2xTdW1zKG10eCkKYGBgCgojIyBVc2luZyBsYXRlbnQKCmBgYHtyfQojbXR4PW10eFtnZW5lX2FubiRWYXJpYW5jZVR5cGU9PSJIVkciLF0KY2RzIDwtIG5ld19jZWxsX2RhdGFfc2V0KG10eCwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uKQojIyBTdGVwIDE6IE5vcm1hbGl6ZSBhbmQgcHJlLXByb2Nlc3MgdGhlIGRhdGEKY2RzIDwtIHByZXByb2Nlc3NfY2RzKGNkcywgbnVtX2RpbSA9IDUwLG1ldGhvZD0iUENBIixub3JtX21ldGhvZD0ibG9nIikKCnRtcDA9cHlfdG9fcihhZGF0YSRvYnNtWyJYX3NjYW5vcmFtYSJdKQpjb2xuYW1lcyh0bXAwKT1wYXN0ZTAoIlBDIiwxOm5jb2wodG1wMCkpCnJlZHVjZWREaW1zKGNkcykkUENBPXRtcDAKCiMjIFN0ZXAgMjogUmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2l0aCBjZWxsIGFsaWdubWVudAojI2NkcyA8LSBhbGlnbl9jZHMoY2RzLCBhbGlnbm1lbnRfZ3JvdXAgPSAiQmF0Y2hJRCIsIHJlc2lkdWFsX21vZGVsX2Zvcm11bGFfc3RyID0gTlVMTCkKIyMgU3RlcCAzOiBSZWR1Y2UgdGhlIGRpbWVuc2lvbnMgdXNpbmcgVU1BUApjZHMgPC0gcmVkdWNlX2RpbWVuc2lvbihjZHMscmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIixwcmVwcm9jZXNzX21ldGhvZD0iUENBIikKCiMjIFN0ZXAgNDogQ2x1c3RlciB0aGUgY2VsbHMKY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzLHJlZHVjdGlvbl9tZXRob2QgPSJVTUFQIixjbHVzdGVyX21ldGhvZCA9ICJsZWlkZW4iKQoKIyBDb25zdHJ1Y3QgdGhlIGdyYXBoCiMgTm90ZSB0aGF0LCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGNvZGUgdG8gcnVuLCB0aGUgZ3JhcGggc2hvdWxkIGJlIGZ1bGx5IChwYXJ0aW9ubHkpIGNvbm5lY3RlZAojIyBTdGVwIDU6IExlYXJuIGEgZ3JhcGgKY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFQsdmVyYm9zZSA9IEYpCmNvbERhdGEoY2RzKSRjbHVzdGVycz1jZHNAY2x1c3RlcnMkVU1BUCRjbHVzdGVycwpwMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLGxhYmVsX2NlbGxfZ3JvdXBzID0gRikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnAyPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXJzIixsYWJlbF9jZWxsX2dyb3Vwcz1GLGdyYXBoX2xhYmVsX3NpemU9MiwgbGFiZWxfbGVhdmVzPUYsbGFiZWxfYnJhbmNoX3BvaW50cz1GKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcD1jb3dwbG90OjpwbG90X2dyaWQocDEscDIsYWxpZ24gPSAiaCIsbmNvbCA9IDMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnAKYGBgCgpgYGB7cn0KIyMgU3RlcCA2OiBPcmRlciBjZWxscwojIHJvb3QgY2VsbHMKaWRzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShjZHMsY2x1c3Rlcj1jKCIyIikpI25lZWQgdG8gc3BlY2lmeQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzPWlkcykKI3Bsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiKQpgYGAKCmBgYHtyLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CmNvbERhdGEoY2RzKSRwc2V1ZG90aW1lPXBzZXVkb3RpbWUoY2RzKQpjb2xEYXRhKGNkcykkUHNldWRvdGltZT1jb2xEYXRhKGNkcykkcHNldWRvdGltZS9tYXgoY29sRGF0YShjZHMpJHBzZXVkb3RpbWUsbmEucm0gPSBUKQojc2F2ZVJEUyhjZHMsZmlsZT0iY2RzX3NjYW5vcmFtYS5yZHMiKQpkZl9kZW49cERhdGEoY2RzKVssYygiUHNldWRvdGltZSIsImRhdGFzZXRfYmF0Y2giKV0KZGZfZGVuPWFzLmRhdGEuZnJhbWUoZGZfZGVuWyFpcy5pbmZpbml0ZShkZl9kZW4kUHNldWRvdGltZSksXSkKc2V0LnNlZWQoMTApCgp0aGVtZV91c2U9dGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpCgpwX21vbm9jbGVfc2Nhbm9yYW1hX2xhdGVudF9odmdfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfbW9ub2NsZV9zY2Fub3JhbWFfbGF0ZW50X2h2Z18yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9zY2Fub3JhbWFfbGF0ZW50X2h2Z18zPWdncGxvdChkYXRhPWRmX2RlbikrZ2VvbV9kZW5zaXR5KGFlcyh4PVBzZXVkb3RpbWUsZmlsbD1kYXRhc2V0X2JhdGNoKSxhbHBoYT0wLjcpKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrdGhlbWVfdXNlCgpwX21vbm9jbGVfc2Nhbm9yYW1hX2xhdGVudF9odmc9ZWdnOjpnZ2FycmFuZ2UocF9tb25vY2xlX3NjYW5vcmFtYV9sYXRlbnRfaHZnXzEscF9tb25vY2xlX3NjYW5vcmFtYV9sYXRlbnRfaHZnXzIscF9tb25vY2xlX3NjYW5vcmFtYV9sYXRlbnRfaHZnXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX3NjYW5vcmFtYV9sYXRlbnRfaHZnCmBgYAoKCmBgYHtyfQojY2RzX2V4cHJzPUZldGNoRGF0YShvYmowLHZhcnMgPSBjKCJGQ0dSM0EiLCJTMTAwQTgiKSkKI2RmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLGNkc19leHBycykpCmNkc19leHBycz1hcy5tYXRyaXgoU2luZ2xlQ2VsbEV4cGVyaW1lbnQ6OmNvdW50cyhjZHMpW2MoIkZDR1IzQSIsIlMxMDBBOCIpLF0pCmRmMD1kYXRhLmZyYW1lKGNiaW5kKHBzZXVkb3RpbWU9cERhdGEoY2RzKSRQc2V1ZG90aW1lLHQoY2RzX2V4cHJzKSkpCmRmMCRVTUFQXzE9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywxXQpkZjAkVU1BUF8yPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMl0KZGYwJEJhdGNoSUQ9cERhdGEoY2RzKSRkYXRhc2V0X2JhdGNoCmRmMD1kZjBbaXMuZmluaXRlKGRmMCRwc2V1ZG90aW1lKSxdCmRmMD1kZjBbb3JkZXIoZGYwJHBzZXVkb3RpbWUsZGVjcmVhc2luZyA9IEYpLCxkcm9wPUZdCmRmMCR4PWRmMCRwc2V1ZG90aW1lL21heChkZjAkcHNldWRvdGltZSkKZGZfcHNldWRvdGltZV9saXN0JHNjYW5vcmFtYV9sYXRlbnRfaHZnPWRmMApgYGAKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKCgpgYGB7cn0KZGZfZGVuPWNvbERhdGEoY2RzKQp0dDE9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDEKdHQyPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSkKdHQyCnR0Mz1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDIiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MwpgYGAKCmBgYHtyfQpTdGFibGU1WzE0LDI6NF09bWF0cml4KGdldF9wX25ldyhjKHR0MSRwLnZhbHVlLHR0MiRwLnZhbHVlLHR0MyRwLnZhbHVlKSxjKHR0MSRzdGF0aXN0aWMsdHQyJHN0YXRpc3RpYyx0dDMkc3RhdGlzdGljKSksMSwzKQpgYGAKCgojIyBIVkdzIGRlbm9pc2VkCgpgYGB7cn0KI2NkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHhbcm93bmFtZXMobXR4KSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsXSwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uW2dlbmVfYW5uJGdlbmVfc2hvcnRfbmFtZSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsLGRyb3A9Rl0pCmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHgsIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubikKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSA1MCxtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCgp0bXAwPXB5X3RvX3IoYWRhdGEkb2JzbVsiWF9odmdwY2EiXSkKY29sbmFtZXModG1wMCk9cGFzdGUwKCJQQyIsMTpuY29sKHRtcDApKQpyZWR1Y2VkRGltcyhjZHMpJFBDQT10bXAwCgojIyBTdGVwIDI6IFJlbW92ZSBiYXRjaCBlZmZlY3RzIHdpdGggY2VsbCBhbGlnbm1lbnQKIyNjZHMgPC0gYWxpZ25fY2RzKGNkcywgYWxpZ25tZW50X2dyb3VwID0gIkJhdGNoSUQiLCByZXNpZHVhbF9tb2RlbF9mb3JtdWxhX3N0ciA9IE5VTEwpCiMjIFN0ZXAgMzogUmVkdWNlIHRoZSBkaW1lbnNpb25zIHVzaW5nIFVNQVAKY2RzIDwtIHJlZHVjZV9kaW1lbnNpb24oY2RzLHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIscHJlcHJvY2Vzc19tZXRob2Q9IlBDQSIsdmVyYm9zZSA9IEYpCgojIyBTdGVwIDQ6IENsdXN0ZXIgdGhlIGNlbGxzCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0iVU1BUCIsY2x1c3Rlcl9tZXRob2QgPSAibGVpZGVuIix2ZXJib3NlID0gRikKCiMgQ29uc3RydWN0IHRoZSBncmFwaAojIE5vdGUgdGhhdCwgZm9yIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIHJ1biwgdGhlIGdyYXBoIHNob3VsZCBiZSBmdWxseSAocGFydGlvbmx5KSBjb25uZWN0ZWQKIyMgU3RlcCA1OiBMZWFybiBhIGdyYXBoCmNkcyA8LSBsZWFybl9ncmFwaChjZHMsIHVzZV9wYXJ0aXRpb24gPSBULHZlcmJvc2UgPSBGKQpjb2xEYXRhKGNkcykkY2x1c3RlcnM9Y2RzQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMKcDE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAicGFydGl0aW9uIixsYWJlbF9jZWxsX2dyb3VwcyA9IEYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwMj1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVycyIsbGFiZWxfY2VsbF9ncm91cHM9RixncmFwaF9sYWJlbF9zaXplPTIsIGxhYmVsX2xlYXZlcz1GLGxhYmVsX2JyYW5jaF9wb2ludHM9RikrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCnA9Y293cGxvdDo6cGxvdF9ncmlkKHAxLHAyLGFsaWduID0gImgiLG5jb2wgPSAzKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CiMjIFN0ZXAgNjogT3JkZXIgY2VsbHMKIyByb290IGNlbGxzCmlkcz1nZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzLGNsdXN0ZXI9YygiMiIpKQpjZHMgPC0gb3JkZXJfY2VsbHMoY2RzLCByb290X3ByX25vZGVzPWlkcykKI3Bsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiKQpgYGAKCgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTE4fQpjb2xEYXRhKGNkcykkcHNldWRvdGltZT1wc2V1ZG90aW1lKGNkcykKY29sRGF0YShjZHMpJFBzZXVkb3RpbWU9Y29sRGF0YShjZHMpJHBzZXVkb3RpbWUvbWF4KGNvbERhdGEoY2RzKSRwc2V1ZG90aW1lLG5hLnJtID0gVCkKZGZfZGVuPXBEYXRhKGNkcylbLGMoIlBzZXVkb3RpbWUiLCJkYXRhc2V0X2JhdGNoIildCmRmX2Rlbj1hcy5kYXRhLmZyYW1lKGRmX2RlblshaXMuaW5maW5pdGUoZGZfZGVuJFBzZXVkb3RpbWUpLF0pCnNldC5zZWVkKDEwKQoKdGhlbWVfdXNlPXRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmdfMT1wbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0X2JhdGNoIiwsZ3JhcGhfbGFiZWxfc2l6ZT0wLGFscGhhPTEsY2VsbF9zaXplID0gMC42KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGE9MC43LCBzaXplPTUpKSkrCiAgdGhlbWVfdXNlKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQogICAgICAgICAgCnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfaHZnXzI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiUHNldWRvdGltZSIsbGFiZWxfYnJhbmNoX3BvaW50cz1ULGdyYXBoX2xhYmVsX3NpemU9MixhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMiksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoYW5nbGU9LTUwICksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjUsImNtIiksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsImNtIikpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvdXJiYXIobGFiZWwucG9zaXRpb24gPSAidG9wIikpK3RoZW1lX3VzZQoKcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmdfMz1nZ3Bsb3QoZGF0YT1kZl9kZW4pK2dlb21fZGVuc2l0eShhZXMoeD1Qc2V1ZG90aW1lLGZpbGw9ZGF0YXNldF9iYXRjaCksYWxwaGE9MC43KSsKICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpK3RoZW1lX3VzZQoKcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmc9ZWdnOjpnZ2FycmFuZ2UocF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmdfMSxwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2h2Z18yLHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfaHZnXzMsbmNvbD0zLGRyYXc9RikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9odmcKYGBgCgpgYGB7cn0KI2Nkc19leHBycz1GZXRjaERhdGEob2JqMCx2YXJzID0gYygiRkNHUjNBIiwiUzEwMEE4IikpCiNkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSxjZHNfZXhwcnMpKQpjZHNfZXhwcnM9YXMubWF0cml4KFNpbmdsZUNlbGxFeHBlcmltZW50Ojpjb3VudHMoY2RzKVtjKCJGQ0dSM0EiLCJTMTAwQTgiKSxdKQpkZjA9ZGF0YS5mcmFtZShjYmluZChwc2V1ZG90aW1lPXBEYXRhKGNkcykkUHNldWRvdGltZSx0KGNkc19leHBycykqbXR4X3NpemVmYWN0b3IpKQpkZjAkVU1BUF8xPXJlZHVjZWREaW1zKGNkcykkVU1BUFssMV0KZGYwJFVNQVBfMj1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDJdCmRmMCRCYXRjaElEPXBEYXRhKGNkcykkZGF0YXNldF9iYXRjaApkZjA9ZGYwW2lzLmZpbml0ZShkZjAkcHNldWRvdGltZSksXQpkZjA9ZGYwW29yZGVyKGRmMCRwc2V1ZG90aW1lLGRlY3JlYXNpbmcgPSBGKSwsZHJvcD1GXQpkZjAkeD1kZjAkcHNldWRvdGltZS9tYXgoZGYwJHBzZXVkb3RpbWUpCmRmX3BzZXVkb3RpbWVfbGlzdCRzY2Fub3JhbWFfZGVub2lzZWRfaHZnPWRmMApgYGAKCi0gRmVhdHVyZSBwbG90cyBvZiBgRkNHUjNBYCBhbmQgYFMxMDBBOGAKCmBgYHtyfQpwPWdldF9wbG90NChkZjAwID0gZGYwKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsZmlnLndpZHRoPTE4fQpwCmBgYAoKYGBge3J9CmRmX2Rlbj1jb2xEYXRhKGNkcykKdHQxPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMSJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQxCnR0Mj1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0pCnR0Mgp0dDM9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQyIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMyJdKQp0dDMKYGBgCgpgYGB7cn0KU3RhYmxlNVsxNSwyOjRdPW1hdHJpeChnZXRfcF9uZXcoYyh0dDEkcC52YWx1ZSx0dDIkcC52YWx1ZSx0dDMkcC52YWx1ZSksYyh0dDEkc3RhdGlzdGljLHR0MiRzdGF0aXN0aWMsdHQzJHN0YXRpc3RpYykpLDEsMykKYGBgCgoKIyMgQWxsIGdlbmVzIGRlbm9pc2VkCgpgYGB7cn0KI2NkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHhbcm93bmFtZXMobXR4KSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsXSwgY2VsbF9tZXRhZGF0YSA9IGNlbGwubWV0YS5kYXRhLGdlbmVfbWV0YWRhdGEgPWdlbmVfYW5uW2dlbmVfYW5uJGdlbmVfc2hvcnRfbmFtZSVpbiVodmdfZ2VuZXMkZ2VuZW5hbWUsLGRyb3A9Rl0pCmNkcyA8LSBuZXdfY2VsbF9kYXRhX3NldChtdHgsIGNlbGxfbWV0YWRhdGEgPSBjZWxsLm1ldGEuZGF0YSxnZW5lX21ldGFkYXRhID1nZW5lX2FubikKIyMgU3RlcCAxOiBOb3JtYWxpemUgYW5kIHByZS1wcm9jZXNzIHRoZSBkYXRhCmNkcyA8LSBwcmVwcm9jZXNzX2NkcyhjZHMsIG51bV9kaW0gPSAzMCxtZXRob2Q9IlBDQSIsbm9ybV9tZXRob2Q9ImxvZyIsdmVyYm9zZSA9IEYpCgp0bXAwPXB5X3RvX3IoYWRhdGEkb2JzbVsiWF9wY2EiXSkKY29sbmFtZXModG1wMCk9cGFzdGUwKCJQQyIsMTpuY29sKHRtcDApKQpyZWR1Y2VkRGltcyhjZHMpJFBDQT10bXAwWywxOjMwXQoKIyMgU3RlcCAyOiBSZW1vdmUgYmF0Y2ggZWZmZWN0cyB3aXRoIGNlbGwgYWxpZ25tZW50CiMjY2RzIDwtIGFsaWduX2NkcyhjZHMsIGFsaWdubWVudF9ncm91cCA9ICJCYXRjaElEIiwgcmVzaWR1YWxfbW9kZWxfZm9ybXVsYV9zdHIgPSBOVUxMKQojIyBTdGVwIDM6IFJlZHVjZSB0aGUgZGltZW5zaW9ucyB1c2luZyBVTUFQCmNkcyA8LSByZWR1Y2VfZGltZW5zaW9uKGNkcyxyZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiLHByZXByb2Nlc3NfbWV0aG9kPSJQQ0EiLHZlcmJvc2UgPSBGKQoKIyMgU3RlcCA0OiBDbHVzdGVyIHRoZSBjZWxscwpjZHMgPC0gY2x1c3Rlcl9jZWxscyhjZHMscmVkdWN0aW9uX21ldGhvZCA9IlVNQVAiLGNsdXN0ZXJfbWV0aG9kID0gImxlaWRlbiIsdmVyYm9zZSA9IEYpCgojIENvbnN0cnVjdCB0aGUgZ3JhcGgKIyBOb3RlIHRoYXQsIGZvciB0aGUgcmVzdCBvZiB0aGUgY29kZSB0byBydW4sIHRoZSBncmFwaCBzaG91bGQgYmUgZnVsbHkgKHBhcnRpb25seSkgY29ubmVjdGVkCiMjIFN0ZXAgNTogTGVhcm4gYSBncmFwaApjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB1c2VfcGFydGl0aW9uID0gVCx2ZXJib3NlID0gRikKY29sRGF0YShjZHMpJGNsdXN0ZXJzPWNkc0BjbHVzdGVycyRVTUFQJGNsdXN0ZXJzCnAxPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gInBhcnRpdGlvbiIsbGFiZWxfY2VsbF9ncm91cHMgPSBGKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcDI9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiY2x1c3RlcnMiLGxhYmVsX2NlbGxfZ3JvdXBzPUYsZ3JhcGhfbGFiZWxfc2l6ZT0yLCBsYWJlbF9sZWF2ZXM9RixsYWJlbF9icmFuY2hfcG9pbnRzPUYpK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwPWNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixhbGlnbiA9ICJoIixuY29sID0gMykKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQojIyBTdGVwIDY6IE9yZGVyIGNlbGxzCiMgcm9vdCBjZWxscwppZHM9Z2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlKGNkcyxjbHVzdGVyPWMoIjEiKSkKY2RzIDwtIG9yZGVyX2NlbGxzKGNkcywgcm9vdF9wcl9ub2Rlcz1pZHMpCiNwbG90X2NlbGxzKGNkcyxjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIikKYGBgCgoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xOH0KY29sRGF0YShjZHMpJHBzZXVkb3RpbWU9cHNldWRvdGltZShjZHMpCmNvbERhdGEoY2RzKSRQc2V1ZG90aW1lPWNvbERhdGEoY2RzKSRwc2V1ZG90aW1lL21heChjb2xEYXRhKGNkcykkcHNldWRvdGltZSxuYS5ybSA9IFQpCmRmX2Rlbj1wRGF0YShjZHMpWyxjKCJQc2V1ZG90aW1lIiwiZGF0YXNldF9iYXRjaCIpXQpkZl9kZW49YXMuZGF0YS5mcmFtZShkZl9kZW5bIWlzLmluZmluaXRlKGRmX2RlbiRQc2V1ZG90aW1lKSxdKQpzZXQuc2VlZCgxMCkKCnRoZW1lX3VzZT10aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkKCnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzE9cGxvdF9jZWxscyhjZHMsY29sb3JfY2VsbHNfYnkgPSAiZGF0YXNldF9iYXRjaCIsLGdyYXBoX2xhYmVsX3NpemU9MCxhbHBoYT0xLGNlbGxfc2l6ZSA9IDAuNikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhPTAuNywgc2l6ZT01KSkpKwogIHRoZW1lX3VzZSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKICAgICAgICAgIApwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2FsbF8yPXBsb3RfY2VsbHMoY2RzLGNvbG9yX2NlbGxzX2J5ID0gIlBzZXVkb3RpbWUiLGxhYmVsX2JyYW5jaF9wb2ludHM9VCxncmFwaF9sYWJlbF9zaXplPTIsYWxwaGE9MSxjZWxsX3NpemUgPSAwLjYpKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjIpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGFuZ2xlPS01MCApLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC41LCJjbSIpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJjbSIpKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3VyYmFyKGxhYmVsLnBvc2l0aW9uID0gInRvcCIpKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzM9Z2dwbG90KGRhdGE9ZGZfZGVuKStnZW9tX2RlbnNpdHkoYWVzKHg9UHNldWRvdGltZSxmaWxsPWRhdGFzZXRfYmF0Y2gpLGFscGhhPTAuNykrCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSt0aGVtZV91c2UKCnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsPWVnZzo6Z2dhcnJhbmdlKHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzEscF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9hbGxfMixwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2FsbF8zLG5jb2w9MyxkcmF3PUYpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9MTh9CnBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsCmBgYAoKYGBge3J9CiNjZHNfZXhwcnM9RmV0Y2hEYXRhKG9iajAsdmFycyA9IGMoIkZDR1IzQSIsIlMxMDBBOCIpKQojZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsY2RzX2V4cHJzKSkKY2RzX2V4cHJzPWFzLm1hdHJpeChTaW5nbGVDZWxsRXhwZXJpbWVudDo6Y291bnRzKGNkcylbYygiRkNHUjNBIiwiUzEwMEE4IiksXSkKZGYwPWRhdGEuZnJhbWUoY2JpbmQocHNldWRvdGltZT1wRGF0YShjZHMpJFBzZXVkb3RpbWUsdChjZHNfZXhwcnMpKm10eF9zaXplZmFjdG9yKSkKZGYwJFVNQVBfMT1yZWR1Y2VkRGltcyhjZHMpJFVNQVBbLDFdCmRmMCRVTUFQXzI9cmVkdWNlZERpbXMoY2RzKSRVTUFQWywyXQpkZjAkQmF0Y2hJRD1wRGF0YShjZHMpJGRhdGFzZXRfYmF0Y2gKZGYwPWRmMFtpcy5maW5pdGUoZGYwJHBzZXVkb3RpbWUpLF0KZGYwPWRmMFtvcmRlcihkZjAkcHNldWRvdGltZSxkZWNyZWFzaW5nID0gRiksLGRyb3A9Rl0KZGYwJHg9ZGYwJHBzZXVkb3RpbWUvbWF4KGRmMCRwc2V1ZG90aW1lKQpkZl9wc2V1ZG90aW1lX2xpc3Qkc2Nhbm9yYW1hX2Rlbm9pc2VkX2FsbD1kZjAKYGBgCgotIEZlYXR1cmUgcGxvdHMgb2YgYEZDR1IzQWAgYW5kIGBTMTAwQThgCgpgYGB7cn0KcD1nZXRfcGxvdDQoZGYwMCA9IGRmMCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LGZpZy53aWR0aD0xOH0KcApgYGAKCmBgYHtyfQpkZl9kZW49Y29sRGF0YShjZHMpCnR0MT1rcy50ZXN0KGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDEiXSxkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQzIl0pCnR0MQp0dDI9a3MudGVzdChkZl9kZW4kUHNldWRvdGltZVtkZl9kZW4kZGF0YXNldF9iYXRjaD09IlQxIl0sZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdKQp0dDIKdHQzPWtzLnRlc3QoZGZfZGVuJFBzZXVkb3RpbWVbZGZfZGVuJGRhdGFzZXRfYmF0Y2g9PSJUMiJdLGRmX2RlbiRQc2V1ZG90aW1lW2RmX2RlbiRkYXRhc2V0X2JhdGNoPT0iVDMiXSkKdHQzCmBgYAoKYGBge3J9ClN0YWJsZTVbMTYsMjo0XT1tYXRyaXgoZ2V0X3BfbmV3KGModHQxJHAudmFsdWUsdHQyJHAudmFsdWUsdHQzJHAudmFsdWUpLGModHQxJHN0YXRpc3RpYyx0dDIkc3RhdGlzdGljLHR0MyRzdGF0aXN0aWMpKSwxLDMpCmBgYAoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGNvd3Bsb3QpKQpgYGAKCmBgYHtyfQojU3VwcGxlbWVudGFyeSBUYWJsZSA1CndyaXRlLnRhYmxlKFN0YWJsZTUsZmlsZT0iS1NfdGFibGUuY3N2IixzZXA9IiwiKQpvcGVueGxzeDo6d3JpdGUueGxzeChTdGFibGU1LGZpbGU9IktTX3RhYmxlLnhsc3giKQoKU3RhYmxlNSAlPiUKICBrYWJsZSgpICU+JQogIGthYmxlX3N0eWxpbmcoKQpgYGAKCiMgRmlndXJlcwoKIyMgIE1haW4gRmlndXJlIChGaWd1cmUgNSkKCmBgYHtyLCBmaWcud2lkdGg9MzAsZmlnLmhlaWdodD0yNX0KZmlnX3dpZHRoPTMwCmZpZ19oZWlnaHQ9MjUKbGFiZWxzPWxldHRlcnNbMTo1XQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKdXNlX2lkPWMoNCwxNSwxMCw3LDEyKQoKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PTAuMDIKICB5PTEtcGxvdF9pZC81CiAgd2lkdGg9MC45OAogIGhlaWdodD0xLzUtMC4wMSAjIHRvdGFsIG51bWJlciBvZiBmaWd1cmVzIGlzIDEyCiAgcHA9ZHJhd19wbG90KGVnZzo6Z2dhcnJhbmdlKHBsb3RzPXBsaXN0MCxucm93ID0gMSxkcmF3ID0gRixuZXdwYWdlID0gRikseCA9IHgseSA9IHksd2lkdGggPSB3aWR0aCxoZWlnaHQgPSBoZWlnaHQpCiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4ocHApCn0KCmdldF9sYWJlbF9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS81LTEvMzApKQp9CgpnZXRfdGl0bGVfcG9zPWZ1bmN0aW9uKHBsb3RfaWQ9MSl7CiAgeD0wLjAxNQogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzEwLTEvNjApKQp9CgpnZXRfcGxvdF9saXN0PWZ1bmN0aW9uKHgseSl7CiAgeDA9cmVwKGxpc3QoKSxsZW5ndGg9bGVuZ3RoKHgpK2xlbmd0aCh5KSkKICB4MFsxOmxlbmd0aCh4KV09eFsxOjNdCiAgeDBbKGxlbmd0aCh4KSsxKTpsZW5ndGgoeDApXT15WzE6Ml0KICByZXR1cm4oeDApCn0KcD1nZ2RyYXcoKStnZXRfZHJhd19wbG90KDEsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfY2FyREVDX2Rlbm9pc2VkX2h2Z18xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfY2FyREVDX2Rlbm9pc2VkX2h2Z18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9jYXJERUNfZGVub2lzZWRfaHZnXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1s0XV0pW2MoMyw0KV0pKSsKZ2V0X2RyYXdfcGxvdCgyLGdldF9wbG90X2xpc3QobGlzdChwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2h2Z18xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX21vbm9jbGVfc2Nhbm9yYW1hX2Rlbm9pc2VkX2h2Z18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfaHZnXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbMTVdXSlbYygzLDQpXSkpKwogIGdldF9kcmF3X3Bsb3QoMyxnZXRfcGxvdF9saXN0KGxpc3QocF9kY2FfZGVub2lzZWRfaHZnXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9kY2FfZGVub2lzZWRfaHZnXzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX2RjYV9kZW5vaXNlZF9odmdfMytzY2FsZV9maWxsX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1sxMF1dKVtjKDMsNCldKSkrCiAgZ2V0X2RyYXdfcGxvdCg0LGdldF9wbG90X2xpc3QobGlzdChwX3NjdmlfZGVub2lzZWRfaHZnXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9zY3ZpX2Rlbm9pc2VkX2h2Z18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9zY3ZpX2Rlbm9pc2VkX2h2Z18zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbN11dKVtjKDMsNCldKSkrCmdldF9kcmF3X3Bsb3QoNSxnZXRfcGxvdF9saXN0KGxpc3QocF9tbm5fZGVub2lzZWRfaHZnXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW5uX2Rlbm9pc2VkX2h2Z18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW5uX2Rlbm9pc2VkX2h2Z18zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzEyXV0pW2MoMyw0KV0pKQoKZm9yIChpIGluIDE6bGVuZ3RoKHVzZV9pZCkpewogIHA9cCtkcmF3X2xhYmVsKGxhYmVsc1tpXSx4PWdldF9sYWJlbF9wb3MoaSlbMV0seT1nZXRfbGFiZWxfcG9zKGkpWzJdLHNpemU9MzAsY29sb3I9ImJsYWNrIixoanVzdCA9IDAsdmp1c3QgPSAxKSsKICAgIGRyYXdfbGFiZWwocGFzdGUwKE1ldGhvZHNbdXNlX2lkW2ldXSxjb2xsYXBzZSA9ICIiKSwKICAgICAgICAgICAgICAgeD1nZXRfdGl0bGVfcG9zKGkpWzFdLAogICAgICAgICAgICAgICB5PWdldF90aXRsZV9wb3MoaSlbMl0sCiAgICAgICAgICAgICAgIHNpemU9MjAsCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIixhbmdsZSA9IDkwLGhqdXN0ID0gMC41LHZqdXN0ID0gMC41KQp9CmBgYAoKYGBge3IsIGZpZy53aWR0aD0zMCxmaWcuaGVpZ2h0PTI1fQpwCmBgYAoKYGBge3J9Cmdnc2F2ZShwLGZpbGVuYW1lID0gIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9NYWluX2ZpZzEucGRmIix3aWR0aCA9IDMwLGhlaWdodCA9IDI1KQpnZ3NhdmUocCxmaWxlbmFtZSA9ICIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfTWFpbl9maWcxLnRpZmYiLHdpZHRoID0gMzAsaGVpZ2h0ID0gMjUsY29tcHJlc3Npb249Imx6dyIpCmBgYAoKCiMjICBTdXBwbGVtZW50YXJ5IEZpZ3VyZXMgYWJvdXQgbW9ub2N5dGUKCjEuIFJhdyAKCmBgYHtyfQpwbGlzdDA9cmVwKGxpc3QoKSxsZW5ndGg9OSkKcGxpc3QwWzE6M109bGlzdChwX29yaV9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikrdGhlbWVfdXNlLAogICAgICAgICAgICAgICAgIHBfb3JpX2FsbF8yLAogICAgICAgICAgICAgICAgIHBfb3JpX2FsbF8zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpK3RoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsMCwxLDApLCJjbSIpKSlbMTozXQpwbGlzdDBbNDo1XT1nZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbMl1dKVsxOjJdCnBsaXN0MFtbNl1dPWdncGxvdCgpK3RoZW1lX3ZvaWQoKSt0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDAsMSwwKSwiY20iKSkKcGxpc3QwWzc6OF09Z2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzJdXSlbMzo0XQpwbGlzdDBbWzldXT1nZ3Bsb3QoKSt0aGVtZV92b2lkKCkKcD1nZ2RyYXcoKStkcmF3X3Bsb3QoZWdnOjpnZ2FycmFuZ2UocGxvdHMgPSBwbGlzdDAsbmNvbD0zLGRyYXcgPSBGKSx4PTAseT0wLHdpZHRoPTEsaGVpZ2h0PTEpKwogZHJhd19sYWJlbCgiYSIseD0wLHk9MS0wLjAyLHNpemU9MzAsY29sb3I9ImJsYWNrIixoanVzdCA9IDAsdmp1c3QgPSAxKSsKIGRyYXdfbGFiZWwoImIiLHg9MCx5PTIvMy0wLjAzLHNpemU9MzAsY29sb3I9ImJsYWNrIixoanVzdCA9IDAsdmp1c3QgPSAxKSsKICAgZHJhd19sYWJlbCgiYyIseD0wLHk9MS8zLTAuMDMsc2l6ZT0zMCxjb2xvcj0iYmxhY2siLGhqdXN0ID0gMCx2anVzdCA9IDEpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTE2fQpwCmBgYAoKYGBge3J9Cmdnc2F2ZShwLGZpbGVuYW1lID0gIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9TdXBwX2ZpZzEucGRmIix3aWR0aCA9IDE4LGhlaWdodCA9IDE2KQpnZ3NhdmUocCxmaWxlbmFtZSA9ICIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWcxLnRpZmYiLHdpZHRoID0gMTgsaGVpZ2h0ID0gMTYsY29tcHJlc3Npb249Imx6dyIpCmBgYAoKMi4gQWxsIGdlbmVzCgpgYGB7cixmaWcud2lkdGg9MzYsZmlnLmhlaWdodD0zMH0KZmlnX3dpZHRoPTMwCmZpZ19oZWlnaHQ9MjUKbGFiZWxzPWxldHRlcnNbMTo1XQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKdXNlX2lkPWMoNSwxNiwxMSw4LDEzKQoKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PTAuMDIKICB5PTEtcGxvdF9pZC81CiAgd2lkdGg9MC45OAogIGhlaWdodD0xLzUtMC4wMSAjIHRvdGFsIG51bWJlciBvZiBmaWd1cmVzIGlzIDEyCiAgcHA9ZHJhd19wbG90KGVnZzo6Z2dhcnJhbmdlKHBsb3RzPXBsaXN0MCxucm93ID0gMSxkcmF3ID0gRixuZXdwYWdlID0gRikseCA9IHgseSA9IHksd2lkdGggPSB3aWR0aCxoZWlnaHQgPSBoZWlnaHQpCiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4ocHApCn0KCmdldF9sYWJlbF9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS81LTEvMzApKQp9CgpnZXRfdGl0bGVfcG9zPWZ1bmN0aW9uKHBsb3RfaWQ9MSl7CiAgeD0wLjAxNQogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzEwLTEvNjApKQp9CmdldF9wbG90X2xpc3Q9ZnVuY3Rpb24oeCx5KXsKICB4MD1yZXAobGlzdCgpLGxlbmd0aD1sZW5ndGgoeCkrbGVuZ3RoKHkpKQogIHgwWzE6bGVuZ3RoKHgpXT14WzE6M10KICB4MFsobGVuZ3RoKHgpKzEpOmxlbmd0aCh4MCldPXlbMToyXQogIHJldHVybih4MCkKfQoKcD1nZ2RyYXcoKSsKICBnZXRfZHJhd19wbG90KDEsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfY2FyREVDX2Rlbm9pc2VkX2FsbF8xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfY2FyREVDX2Rlbm9pc2VkX2FsbF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9jYXJERUNfZGVub2lzZWRfYWxsXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbNV1dKVtjKDMsNCldKSkrCiBnZXRfZHJhd19wbG90KDIsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW9ub2NsZV9zY2Fub3JhbWFfZGVub2lzZWRfYWxsXzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9tb25vY2xlX3NjYW5vcmFtYV9kZW5vaXNlZF9hbGxfMytzY2FsZV9maWxsX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1sxNl1dKVtjKDMsNCldKSkrCiAgZ2V0X2RyYXdfcGxvdCgzLGdldF9wbG90X2xpc3QobGlzdChwX2RjYV9kZW5vaXNlZF9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX2RjYV9kZW5vaXNlZF9hbGxfMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfZGNhX2Rlbm9pc2VkX2FsbF8zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzExXV0pW2MoMyw0KV0pKSsKICBnZXRfZHJhd19wbG90KDQsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfc2NWSV9kZW5vaXNlZF9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3NjVklfZGVub2lzZWRfYWxsXzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3NjVklfZGVub2lzZWRfYWxsXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbOF1dKVtjKDMsNCldKSkrCiAgZ2V0X2RyYXdfcGxvdCg1LGdldF9wbG90X2xpc3QobGlzdChwX21ubl9kZW5vaXNlZF9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX21ubl9kZW5vaXNlZF9hbGxfMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfbW5uX2Rlbm9pc2VkX2FsbF8zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzEzXV0pW2MoMyw0KV0pKQogCmZvciAoaSBpbiAxOmxlbmd0aCh1c2VfaWQpKXsKICBwPXArZHJhd19sYWJlbChsYWJlbHNbaV0seD1nZXRfbGFiZWxfcG9zKGkpWzFdLHk9Z2V0X2xhYmVsX3BvcyhpKVsyXSxzaXplPTMwLGNvbG9yPSJibGFjayIsaGp1c3QgPSAwLHZqdXN0ID0gMSkrCiAgICBkcmF3X2xhYmVsKHBhc3RlMChNZXRob2RzW3VzZV9pZFtpXV0sY29sbGFwc2UgPSAiIiksCiAgICAgICAgICAgICAgIHg9Z2V0X3RpdGxlX3BvcyhpKVsxXSwKICAgICAgICAgICAgICAgeT1nZXRfdGl0bGVfcG9zKGkpWzJdLAogICAgICAgICAgICAgICBzaXplPTIwLAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsYW5nbGUgPSA5MCxoanVzdCA9IDAuNSx2anVzdCA9IDAuNSkKfQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MzAsZmlnLmhlaWdodD0yNX0KcApgYGAKCmBgYHtyfQpnZ3NhdmUocCxmaWxlbmFtZSA9ICIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWcyLnBkZiIsd2lkdGggPSAzMCxoZWlnaHQgPSAyNSxsaW1pdHNpemUgPSBGKQpnZ3NhdmUocCxmaWxlbmFtZSA9ICIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWcyLnRpZmYiLHdpZHRoID0gMzAsaGVpZ2h0ID0gMjUsbGltaXRzaXplID0gRixjb21wcmVzc2lvbj0ibHp3IikKYGBgCgoKMy4gTGF0ZW50CgpgYGB7cixmaWcud2lkdGg9MzYsZmlnLmhlaWdodD0zMH0KZmlnX3dpZHRoPTMwCmZpZ19oZWlnaHQ9MjUKbGFiZWxzPWxldHRlcnNbMTo1XQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKCnVzZV9pZD1jKDMsMTQsOSw2LDEpCgpnZXRfZHJhd19wbG90PWZ1bmN0aW9uKHBsb3RfaWQ9MSxwbGlzdDApewogIHg9MC4wMgogIHk9MS1wbG90X2lkLzUKICB3aWR0aD0wLjk4CiAgaGVpZ2h0PTEvNS0wLjAxICMgdG90YWwgbnVtYmVyIG9mIGZpZ3VyZXMgaXMgMTIKICBwcD1kcmF3X3Bsb3QoZWdnOjpnZ2FycmFuZ2UocGxvdHM9cGxpc3QwLG5yb3cgPSAxLGRyYXcgPSBGLG5ld3BhZ2UgPSBGKSx4ID0geCx5ID0geSx3aWR0aCA9IHdpZHRoLGhlaWdodCA9IGhlaWdodCkKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihwcCkKfQoKZ2V0X2xhYmVsX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9MAogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzUtMS8zMCkpCn0KCmdldF90aXRsZV9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAuMDE1CiAgeT0xLXBsb3RfaWQvNQogICNkcmF3X2xhYmVsKGxhYmVsc1twbG90X2lkXSx4PXgseT15KzEvNixoanVzdCA9MSx2anVzdCA9IDAuNSxzaXplID0gMzUpCiAgcmV0dXJuKGMoeCx5KzEvMTAtMS82MCkpCn0KZ2V0X3Bsb3RfbGlzdD1mdW5jdGlvbih4LHkpewogIHgwPXJlcChsaXN0KCksbGVuZ3RoPWxlbmd0aCh4KStsZW5ndGgoeSkpCiAgeDBbMTpsZW5ndGgoeCldPXhbMTozXQogIHgwWyhsZW5ndGgoeCkrMSk6bGVuZ3RoKHgwKV09eVsxOjJdCiAgcmV0dXJuKHgwKQp9CgoKcD1nZ2RyYXcoKStnZXRfZHJhd19wbG90KDEsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfY2FyREVDX2xhdGVudF8xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfY2FyREVDX2xhdGVudF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9jYXJERUNfbGF0ZW50XzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1szXV0pW2MoMyw0KV0pKSsKICBnZXRfZHJhd19wbG90KDIsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfbW9ub2NsZV9zY2Fub3JhbWFfbGF0ZW50X2h2Z18xK3NjYWxlX2NvbG9yX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX21vbm9jbGVfc2Nhbm9yYW1hX2xhdGVudF9odmdfMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX21vbm9jbGVfc2Nhbm9yYW1hX2xhdGVudF9odmdfMytzY2FsZV9maWxsX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1sxNF1dKVtjKDMsNCldKSkrCiAgZ2V0X2RyYXdfcGxvdCgzLGdldF9wbG90X2xpc3QobGlzdChwX2RjYV9sYXRlbnRfYWxsXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9kY2FfbGF0ZW50X2FsbF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9kY2FfbGF0ZW50X2FsbF8zK3NjYWxlX2ZpbGxfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbWzldXSlbYygzLDQpXSkpKwogIGdldF9kcmF3X3Bsb3QoNCxnZXRfcGxvdF9saXN0KGxpc3QocF9zY1ZJX2xhdGVudF9hbGxfMStzY2FsZV9jb2xvcl9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3NjVklfbGF0ZW50X2FsbF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9zY1ZJX2xhdGVudF9hbGxfMytzY2FsZV9maWxsX2JyZXdlcihuYW1lPSJkYXRhc2V0X2JhdGNoIixwYWxldHRlID0gIlNldDIiKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldF9wbG90NF9zZXAoZGZfcHNldWRvdGltZV9saXN0W1s2XV0pW2MoMyw0KV0pKSsKICBnZXRfZHJhd19wbG90KDUsZ2V0X3Bsb3RfbGlzdChsaXN0KHBfb3JpXzErc2NhbGVfY29sb3JfYnJld2VyKG5hbWU9ImRhdGFzZXRfYmF0Y2giLHBhbGV0dGUgPSAiU2V0MiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF9vcmlfMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfb3JpXzMrc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iZGF0YXNldF9iYXRjaCIscGFsZXR0ZSA9ICJTZXQyIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbMV1dKVtjKDMsNCldKSkKZm9yIChpIGluIDE6bGVuZ3RoKHVzZV9pZCkpewogIHA9cCtkcmF3X2xhYmVsKGxhYmVsc1tpXSx4PWdldF9sYWJlbF9wb3MoaSlbMV0seT1nZXRfbGFiZWxfcG9zKGkpWzJdLHNpemU9MzAsY29sb3I9ImJsYWNrIixoanVzdCA9IDAsdmp1c3QgPSAxKSsKICAgIGRyYXdfbGFiZWwocGFzdGUwKE1ldGhvZHNbdXNlX2lkW2ldXSxjb2xsYXBzZSA9ICIiKSwKICAgICAgICAgICAgICAgeD1nZXRfdGl0bGVfcG9zKGkpWzFdLAogICAgICAgICAgICAgICB5PWdldF90aXRsZV9wb3MoaSlbMl0sCiAgICAgICAgICAgICAgIHNpemU9MjAsCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIixhbmdsZSA9IDkwLGhqdXN0ID0gMC41LHZqdXN0ID0gMC41KQp9CmBgYAoKYGBge3IsIGZpZy53aWR0aD0zMCxmaWcuaGVpZ2h0PTI1fQpwCmBgYAoKYGBge3J9Cmdnc2F2ZShwLGZpbGVuYW1lID0gIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9TdXBwX2ZpZzMucGRmIix3aWR0aCA9IDMwLGhlaWdodCA9IDI1LGxpbWl0c2l6ZSA9IEYpCmdnc2F2ZShwLGZpbGVuYW1lID0gIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9TdXBwX2ZpZzMudGlmZiIsd2lkdGggPSAzMCxoZWlnaHQgPSAyNSxsaW1pdHNpemUgPSBGLGNvbXByZXNzaW9uPSJsenciKQpgYGAKCiMjIFMxMDBBOCBhbmQgRkNHUjNBJ3MgZmVhdHVyZSBwbG90cwoKMS4gbW9ub2NsZXMnIFVNQVAgb2YgZGVub2lzZWQgY291bnRzIGZyb20gSFZHcyAKCmBgYHtyfQpmaWdfd2lkdGg9MTUKZmlnX2hlaWdodD0yNQpsYWJlbHM9bGV0dGVyc1sxOjEzXQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKdXNlX2lkPWMoNCwxNSwxMCw3LDEyKQojdXNlX2lkPWMoMyw5LDYsMSkKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PTAuMDIKICB5PTEtcGxvdF9pZC81CiAgd2lkdGg9MC45OAogIGhlaWdodD0xLzUtMC4wMSAjIHRvdGFsIG51bWJlciBvZiBmaWd1cmVzIGlzIDEyCiAgcHA9ZHJhd19wbG90KGVnZzo6Z2dhcnJhbmdlKHBsb3RzPXBsaXN0MCxucm93ID0gMSxkcmF3ID0gRixuZXdwYWdlID0gRikseCA9IHgseSA9IHksd2lkdGggPSB3aWR0aCxoZWlnaHQgPSBoZWlnaHQpCiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4ocHApCn0KCmdldF9sYWJlbF9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS81LTEvMTAwKSkKfQoKZ2V0X3RpdGxlX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9MC4wMTUKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS8xMC0xLzEwMCkpCn0KZ2V0X3Bsb3RfbGlzdD1mdW5jdGlvbih4LHkpewogIHgwPXJlcChsaXN0KCksbGVuZ3RoPWxlbmd0aCh4KStsZW5ndGgoeSkpCiAgeDBbMTpsZW5ndGgoeCldPXhbMTozXQogIHgwWyhsZW5ndGgoeCkrMSk6bGVuZ3RoKHgwKV09eVsxOjJdCiAgcmV0dXJuKHgwKQp9CgpwPWdnZHJhdygpCmZvcihpIGluIDE6bGVuZ3RoKHVzZV9pZCkpewogIHA9cCtnZXRfZHJhd19wbG90KGksZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbW3VzZV9pZFtpXV1dKVtjKDEsMildKQp9Cgpmb3IgKGkgaW4gMTpsZW5ndGgodXNlX2lkKSl7CiAgcD1wK2RyYXdfbGFiZWwobGFiZWxzW2ldLHg9Z2V0X2xhYmVsX3BvcyhpKVsxXSx5PWdldF9sYWJlbF9wb3MoaSlbMl0sc2l6ZT0zMCxjb2xvcj0iYmxhY2siLGhqdXN0ID0gMCx2anVzdCA9IDEpKwogICAgZHJhd19sYWJlbChwYXN0ZTAoTWV0aG9kc1t1c2VfaWRbaV1dLGNvbGxhcHNlID0gIiIpLAogICAgICAgICAgICAgICB4PWdldF90aXRsZV9wb3MoaSlbMV0sCiAgICAgICAgICAgICAgIHk9Z2V0X3RpdGxlX3BvcyhpKVsyXSwKICAgICAgICAgICAgICAgc2l6ZT0yMCwKICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLGFuZ2xlID0gOTAsaGp1c3QgPSAwLjUsdmp1c3QgPSAwLjUpCn0KCmBgYAoKYGBge3IgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjV9Cmdnc2F2ZSgiLi9yZXZpc2VkX2ZpZ3VyZXMvQ2FyREVDX21vbm9jeXRlX1N1cHBfZmlnNC5wZGYiLHAsd2lkdGggPSAxNSxoZWlnaHQgPSAyNSkKZ2dzYXZlKCIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWc0LnRpZmYiLHAsd2lkdGggPSAxNSxoZWlnaHQgPSAyNSxjb21wcmVzc2lvbj0ibHp3IikKcApgYGAKCjIuIG1vbm9jbGVzJyBVTUFQIG9mIGRlbm9pc2VkIGNvdW50cyBmcm9tIEFsbCBnZW5lcyAKCgpgYGB7cn0KZmlnX3dpZHRoPTE1CmZpZ19oZWlnaHQ9MjUKbGFiZWxzPWxldHRlcnNbMToxM10KTWV0aG9kcz1jKCJSYXcgY291bnQgSFZHcyIsIlJhdyBjb3VudCBBbGwiLCJDYXJERUMgKGxhdGVudCkiLCJDYXJERUMgKGRlbm9pc2VkIEhWR3MpIiwiQ2FyREVDIChkZW5vaXNlZCBBbGwpIiwic2NWSSAobGF0ZW50KSIsInNjVkkgKGRlbm9pc2VkIEhWR3MpIiwic2NWSSAoZGVub2lzZWQgQWxsKSIsIkRDQSAobGF0ZW50KSIsIkRDQSAoZGVub2lzZWQgSFZHcykiLCJEQ0EgKGRlbm9pc2VkIEFsbCkiLCJNTk4gKGRlbm9pc2VkIEhWR3MpIiwiTU5OIChkZW5vaXNlZCBBbGwpIiwiU2Nhbm9yYW1hIChsYXRlbnQpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBIVkdzKSIsIlNjYW5vcmFtYSAoZGVub2lzZWQgQWxsKSIpCnVzZV9pZD1jKDUsMTYsMTEsOCwxMykKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PTAuMDIKICB5PTEtcGxvdF9pZC81CiAgd2lkdGg9MC45OAogIGhlaWdodD0xLzUtMC4wMSAjIHRvdGFsIG51bWJlciBvZiBmaWd1cmVzIGlzIDEyCiAgcHA9ZHJhd19wbG90KGVnZzo6Z2dhcnJhbmdlKHBsb3RzPXBsaXN0MCxucm93ID0gMSxkcmF3ID0gRixuZXdwYWdlID0gRikseCA9IHgseSA9IHksd2lkdGggPSB3aWR0aCxoZWlnaHQgPSBoZWlnaHQpCiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4ocHApCn0KCmdldF9sYWJlbF9wb3M9ZnVuY3Rpb24ocGxvdF9pZD0xKXsKICB4PTAKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS81LTEvMTAwKSkKfQoKZ2V0X3RpdGxlX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9MC4wMTUKICB5PTEtcGxvdF9pZC81CiAgI2RyYXdfbGFiZWwobGFiZWxzW3Bsb3RfaWRdLHg9eCx5PXkrMS82LGhqdXN0ID0xLHZqdXN0ID0gMC41LHNpemUgPSAzNSkKICByZXR1cm4oYyh4LHkrMS8xMC0xLzEwMCkpCn0KZ2V0X3Bsb3RfbGlzdD1mdW5jdGlvbih4LHkpewogIHgwPXJlcChsaXN0KCksbGVuZ3RoPWxlbmd0aCh4KStsZW5ndGgoeSkpCiAgeDBbMTpsZW5ndGgoeCldPXhbMTozXQogIHgwWyhsZW5ndGgoeCkrMSk6bGVuZ3RoKHgwKV09eVsxOjJdCiAgcmV0dXJuKHgwKQp9CgpwPWdnZHJhdygpCmZvcihpIGluIDE6bGVuZ3RoKHVzZV9pZCkpewogIHA9cCtnZXRfZHJhd19wbG90KGksZ2V0X3Bsb3Q0X3NlcChkZl9wc2V1ZG90aW1lX2xpc3RbW3VzZV9pZFtpXV1dKVtjKDEsMildKQp9Cgpmb3IgKGkgaW4gMTpsZW5ndGgodXNlX2lkKSl7CiAgcD1wK2RyYXdfbGFiZWwobGFiZWxzW2ldLHg9Z2V0X2xhYmVsX3BvcyhpKVsxXSx5PWdldF9sYWJlbF9wb3MoaSlbMl0sc2l6ZT0zMCxjb2xvcj0iYmxhY2siLGhqdXN0ID0gMCx2anVzdCA9IDEpKwogICAgZHJhd19sYWJlbChwYXN0ZTAoTWV0aG9kc1t1c2VfaWRbaV1dLGNvbGxhcHNlID0gIiIpLAogICAgICAgICAgICAgICB4PWdldF90aXRsZV9wb3MoaSlbMV0sCiAgICAgICAgICAgICAgIHk9Z2V0X3RpdGxlX3BvcyhpKVsyXSwKICAgICAgICAgICAgICAgc2l6ZT0yMCwKICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLGFuZ2xlID0gOTAsaGp1c3QgPSAwLjUsdmp1c3QgPSAwLjUpCn0KCmBgYAoKYGBge3IgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjV9Cmdnc2F2ZSgiLi9yZXZpc2VkX2ZpZ3VyZXMvQ2FyREVDX21vbm9jeXRlX1N1cHBfZmlnNS5wZGYiLHAsd2lkdGggPSAxNSxoZWlnaHQgPSAyNSkKZ2dzYXZlKCIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWc1LnRpZmYiLHAsd2lkdGggPSAxNSxoZWlnaHQgPSAyNSxjb21wcmVzc2lvbj0ibHp3IikKcApgYGAKCgozLiBtb25vY2xlcycgVU1BUCBiYXNlZCBvbiBkaWZmZXJlbnQgbWV0aG9kcycgbGF0ZW50CgoKYGBge3J9CmZpZ193aWR0aD0xNQpmaWdfaGVpZ2h0PTI1CmxhYmVscz1sZXR0ZXJzWzE6MTNdCk1ldGhvZHM9YygiUmF3IGNvdW50IEhWR3MiLCJSYXcgY291bnQgQWxsIiwiQ2FyREVDIChsYXRlbnQpIiwiQ2FyREVDIChkZW5vaXNlZCBIVkdzKSIsIkNhckRFQyAoZGVub2lzZWQgQWxsKSIsInNjVkkgKGxhdGVudCkiLCJzY1ZJIChkZW5vaXNlZCBIVkdzKSIsInNjVkkgKGRlbm9pc2VkIEFsbCkiLCJEQ0EgKGxhdGVudCkiLCJEQ0EgKGRlbm9pc2VkIEhWR3MpIiwiRENBIChkZW5vaXNlZCBBbGwpIiwiTU5OIChkZW5vaXNlZCBIVkdzKSIsIk1OTiAoZGVub2lzZWQgQWxsKSIsIlNjYW5vcmFtYSAobGF0ZW50KSIsIlNjYW5vcmFtYSAoZGVub2lzZWQgSFZHcykiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEFsbCkiKQp1c2VfaWQ9YygzLDE0LDksNiwxKQpnZXRfZHJhd19wbG90PWZ1bmN0aW9uKHBsb3RfaWQ9MSxwbGlzdDApewogIHg9MC4wMgogIHk9MS1wbG90X2lkLzUKICB3aWR0aD0wLjk4CiAgaGVpZ2h0PTEvNS0wLjAxICMgdG90YWwgbnVtYmVyIG9mIGZpZ3VyZXMgaXMgMTIKICBwcD1kcmF3X3Bsb3QoZWdnOjpnZ2FycmFuZ2UocGxvdHM9cGxpc3QwLG5yb3cgPSAxLGRyYXcgPSBGLG5ld3BhZ2UgPSBGKSx4ID0geCx5ID0geSx3aWR0aCA9IHdpZHRoLGhlaWdodCA9IGhlaWdodCkKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihwcCkKfQoKZ2V0X2xhYmVsX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9MAogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzUtMS8xMDApKQp9CgpnZXRfdGl0bGVfcG9zPWZ1bmN0aW9uKHBsb3RfaWQ9MSl7CiAgeD0wLjAxNQogIHk9MS1wbG90X2lkLzUKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzEwLTEvMTAwKSkKfQpnZXRfcGxvdF9saXN0PWZ1bmN0aW9uKHgseSl7CiAgeDA9cmVwKGxpc3QoKSxsZW5ndGg9bGVuZ3RoKHgpK2xlbmd0aCh5KSkKICB4MFsxOmxlbmd0aCh4KV09eFsxOjNdCiAgeDBbKGxlbmd0aCh4KSsxKTpsZW5ndGgoeDApXT15WzE6Ml0KICByZXR1cm4oeDApCn0KCnA9Z2dkcmF3KCkKZm9yKGkgaW4gMTpsZW5ndGgodXNlX2lkKSl7CiAgcD1wK2dldF9kcmF3X3Bsb3QoaSxnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbdXNlX2lkW2ldXV0pW2MoMSwyKV0pCn0KCmZvciAoaSBpbiAxOmxlbmd0aCh1c2VfaWQpKXsKICBwPXArZHJhd19sYWJlbChsYWJlbHNbaV0seD1nZXRfbGFiZWxfcG9zKGkpWzFdLHk9Z2V0X2xhYmVsX3BvcyhpKVsyXSxzaXplPTMwLGNvbG9yPSJibGFjayIsaGp1c3QgPSAwLHZqdXN0ID0gMSkrCiAgICBkcmF3X2xhYmVsKHBhc3RlMChNZXRob2RzW3VzZV9pZFtpXV0sY29sbGFwc2UgPSAiIiksCiAgICAgICAgICAgICAgIHg9Z2V0X3RpdGxlX3BvcyhpKVsxXSwKICAgICAgICAgICAgICAgeT1nZXRfdGl0bGVfcG9zKGkpWzJdLAogICAgICAgICAgICAgICBzaXplPTIwLAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsYW5nbGUgPSA5MCxoanVzdCA9IDAuNSx2anVzdCA9IDAuNSkKfQoKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0yNX0KZ2dzYXZlKCIuL3JldmlzZWRfZmlndXJlcy9DYXJERUNfbW9ub2N5dGVfU3VwcF9maWc2LnBkZiIscCx3aWR0aCA9IDE1LGhlaWdodCA9IDI1KQpnZ3NhdmUoIi4vcmV2aXNlZF9maWd1cmVzL0NhckRFQ19tb25vY3l0ZV9TdXBwX2ZpZzYudGlmZiIscCx3aWR0aCA9IDE1LGhlaWdodCA9IDI1LGNvbXByZXNzaW9uPSJsenciKQpwCmBgYAoKNC4gQ29tYmluZWQgYWJvdmUgdGhyZWUgZmlndXJlcwoKYGBge3J9CmZpZ193aWR0aD0yNApmaWdfaGVpZ2h0PTM2IwpsYWJlbHM9bGV0dGVyc1sxOjE2XQpNZXRob2RzPWMoIlJhdyBjb3VudCBIVkdzIiwiUmF3IGNvdW50IEFsbCIsIkNhckRFQyAobGF0ZW50KSIsIkNhckRFQyAoZGVub2lzZWQgSFZHcykiLCJDYXJERUMgKGRlbm9pc2VkIEFsbCkiLCJzY1ZJIChsYXRlbnQpIiwic2NWSSAoZGVub2lzZWQgSFZHcykiLCJzY1ZJIChkZW5vaXNlZCBBbGwpIiwiRENBIChsYXRlbnQpIiwiRENBIChkZW5vaXNlZCBIVkdzKSIsIkRDQSAoZGVub2lzZWQgQWxsKSIsIk1OTiAoZGVub2lzZWQgSFZHcykiLCJNTk4gKGRlbm9pc2VkIEFsbCkiLCJTY2Fub3JhbWEgKGxhdGVudCkiLCJTY2Fub3JhbWEgKGRlbm9pc2VkIEhWR3MpIiwiU2Nhbm9yYW1hIChkZW5vaXNlZCBBbGwpIikKdXNlX2lkPWMoMSwzOjUsMTQ6MTYsNjoxMykKZ2V0X2RyYXdfcGxvdD1mdW5jdGlvbihwbG90X2lkPTEscGxpc3QwKXsKICB4PWlmZWxzZShwbG90X2lkJSUyPT0xLDAsMC41MDc1KQogIHk9MS1mbG9vcigocGxvdF9pZCsxKS8yKS84CiAgd2lkdGg9MS8yLTAuMDE1CiAgaGVpZ2h0PTEvOC0wLjAxICMgdG90YWwgbnVtYmVyIG9mIGZpZ3VyZXMgaXMgMTIKICBwcD1kcmF3X3Bsb3QoZWdnOjpnZ2FycmFuZ2UocGxvdHM9cGxpc3QwLG5jb2wgPSAyLGRyYXcgPSBGLG5ld3BhZ2UgPSBGKSx4ID0geCx5ID0geSx3aWR0aCA9IHdpZHRoLGhlaWdodCA9IGhlaWdodCkKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihwcCkKfQoKZ2V0X2xhYmVsX3Bvcz1mdW5jdGlvbihwbG90X2lkPTEpewogIHg9aWZlbHNlKHBsb3RfaWQlJTI9PTEsMCwwLjUwNzUpCiAgeT0xLWZsb29yKChwbG90X2lkKzEpLzIpLzgKICAjZHJhd19sYWJlbChsYWJlbHNbcGxvdF9pZF0seD14LHk9eSsxLzYsaGp1c3QgPTEsdmp1c3QgPSAwLjUsc2l6ZSA9IDM1KQogIHJldHVybihjKHgseSsxLzgtMS8xMDApKQp9CgpnZXRfdGl0bGVfcG9zPWZ1bmN0aW9uKHBsb3RfaWQ9MSl7CiAgeD1pZmVsc2UocGxvdF9pZCUlMj09MSwwLDAuNTA3NSkrMC41LzIKICB5PTEtZmxvb3IoKHBsb3RfaWQrMSkvMikvOAogICNkcmF3X2xhYmVsKGxhYmVsc1twbG90X2lkXSx4PXgseT15KzEvNixoanVzdCA9MSx2anVzdCA9IDAuNSxzaXplID0gMzUpCiAgcmV0dXJuKGMoeCx5KzEvOC0xLzMwMCkpCn0KCnA9Z2dkcmF3KCkKZm9yKGkgaW4gMTpsZW5ndGgodXNlX2lkKSl7CiAgcD1wK2dldF9kcmF3X3Bsb3QoaSxnZXRfcGxvdDRfc2VwKGRmX3BzZXVkb3RpbWVfbGlzdFtbdXNlX2lkW2ldXV0pW2MoMSwyKV0pCn0KCmZvciAoaSBpbiAxOmxlbmd0aCh1c2VfaWQpKXsKICBwPXArZHJhd19sYWJlbChsYWJlbHNbaV0seD1nZXRfbGFiZWxfcG9zKGkpWzFdLHk9Z2V0X2xhYmVsX3BvcyhpKVsyXSxzaXplPTE4LGNvbG9yPSJibGFjayIsaGp1c3QgPSAwLHZqdXN0ID0gMSkrCiAgICBkcmF3X2xhYmVsKHBhc3RlMChNZXRob2RzW3VzZV9pZFtpXV0sY29sbGFwc2UgPSAiIikseD1nZXRfdGl0bGVfcG9zKGkpWzFdLHk9Z2V0X3RpdGxlX3BvcyhpKVsyXSxzaXplPTI1LGNvbG9yID0gImJsYWNrIix2anVzdCA9IDEpCn0KCmBgYAoKYGBge3IgZmlnLndpZHRoPTI0LGZpZy5oZWlnaHQ9MzZ9CnAKYGBgCgpgYGB7cn0KZ2dzYXZlKHAsZmlsZW5hbWUgPSAiLi9yZXZpc2VkX2ZpZ3VyZXMvQ2FyREVDX21vbm9jeXRlX1N1cHBfZmlnNDU2X2NvbWJpbmVkLnBkZiIsd2lkdGggPSAyNCxoZWlnaHQgPSAzNikKZ2dzYXZlKHAsZmlsZW5hbWUgPSAiLi9yZXZpc2VkX2ZpZ3VyZXMvQ2FyREVDX21vbm9jeXRlX1N1cHBfZmlnNDU2X2NvbWJpbmVkLnRpZmYiLHdpZHRoID0gMjQsaGVpZ2h0ID0gMzYsY29tcHJlc3Npb249Imx6dyIpCmBgYAoKCmBgYHtyfQojc2F2ZSBvYmplY3QgCnJtKG10eCkKcm0ob3V0cHV0KQpybShhZGF0YSkKcm0oY2RzKQpybShvYmowKQpybShyYXcuZGF0YSkKZ2MoKQpzYXZlLmltYWdlKGZpbGU9ImNhckRFQ19tb25vY3l0ZV9maW5hbF9yZXZpc2VkLlJEYXRhIikjaW5jbHVkZSBzY2Fub3JhbWEsY2FyREVDX21vbm9jeXRlX2ZpbmFsLlJEYXRhIG5vdCBpbmNsdWRlIHNjYW5vcmFtYQojbG9hZCgiY2FyREVDX21vbm9jeXRlX2ZpbmFsX3JldmlzZWQuUkRhdGEiKQpgYGAKCmBgYHtyfQojbG9hZCgiY2FyREVDX21vbm9jeXRlX2ZpbmFsX3JldmlzZWQuUkRhdGEiKQpgYGAKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAo=